scripts: use WpConf API to get configuration values

This patch also moves nested configuration objects that are not considered
settings from the wireplumber.settings section to its own configuration
section (eg the rules array, the spa plugin properties, etc...). This allows
those objects to be merged with other same sections defined in other files.
This commit is contained in:
Julian Bouzas 2023-01-10 09:11:15 -05:00
parent 6c6d5eccf9
commit 360e0b3eaf
27 changed files with 594 additions and 1587 deletions

View file

@ -8,11 +8,11 @@
#define G_LOG_DOMAIN "wp-settings"
#include <wp/wp.h>
#include "core.h"
#include "settings.h"
#include "metadata.h"
#include "log.h"
#include "object-manager.h"
#include "private/registry.h"
/*! \defgroup wpsettings WpSettings */
@ -20,8 +20,8 @@
* \struct WpSettings
*
* WpSettings loads and parses the "sm-settings" (default value) metadata, which
* contains wireplumber settings and rules. It provides APIs to its clients
* (modules, lua scripts etc) to access and change them.
* contains wireplumber settings. It 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.
@ -33,9 +33,6 @@ struct _WpSettings
WpProperties *settings;
/* element-type: Rule* */
GPtrArray *rules;
/* element-type: Callback* */
GPtrArray *callbacks;
@ -43,20 +40,6 @@ struct _WpSettings
WpObjectManager *metadata_om;
};
typedef struct
{
gchar *rule;
/* element-type: Match* */
GPtrArray *matches;
} Rule;
typedef struct
{
/* element-type: WpObjectInterest* */
GPtrArray *interests;
WpProperties *actions;
} Match;
typedef struct
{
GClosure *closure;
@ -185,159 +168,6 @@ wp_settings_get (WpSettings *self, const gchar *setting)
return value ? wp_spa_json_new_from_string (value) : NULL;
}
/*!
* \brief Safely parses a boolean setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
gboolean
wp_settings_parse_boolean_safe (WpSettings *self, const gchar *setting,
gboolean value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
gboolean res = value;
if (json && !wp_spa_json_parse_boolean (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as boolean",
setting);
return res;
}
/*!
* \brief Safely parses an integer setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
gint
wp_settings_parse_int_safe (WpSettings *self, const gchar *setting, gint value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
gint res = value;
if (json && !wp_spa_json_parse_int (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as int", setting);
return res;
}
/*!
* \brief Safely parses a float setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
float
wp_settings_parse_float_safe (WpSettings *self, const gchar *setting,
float value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
float res = value;
if (json && !wp_spa_json_parse_float (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as float", setting);
return res;
}
/*!
* \brief Safely parses a string setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns (transfer full): The value of the setting, or the fallback value in
* case of error
*/
gchar *
wp_settings_parse_string_safe (WpSettings *self, const gchar *setting,
const gchar *value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
if (json) {
gchar *res = wp_spa_json_parse_string (json);
if (res)
return res;
else
wp_warning_object (self, "Could not parse setting '%s' as string",
setting);
}
return g_strdup (value);
}
/*!
* \brief Applies the rules and returns the applied properties.
*
* This function applies the rules on the client properties and if
* there is a match, it returns TRUE and also copies the applied properties.
*
* \ingroup wpsettings
* \param self the settings object
* \param rule name of the rule; this will match with the section mentioned
* in the conf file.
* \param client_props (transfer none)(inout): client properties array; these
* properties are inputs on which the rules are applied.
* \param applied_props (transfer none)(nullable)(out): the resultant
* actions/properties as a result of the application of rules are copied;
* if this is NULL, properties will be appended to \a client_props instead
* \returns TRUE if there is a match for the client_props and the
* applied properties are returned, FALSE otherwise
*/
gboolean
wp_settings_apply_rule (WpSettings *self, const gchar *rule,
WpProperties *client_props, WpProperties *applied_props)
{
g_return_val_if_fail (WP_IS_SETTINGS (self), FALSE);
g_return_val_if_fail (rule, FALSE);
g_return_val_if_fail (client_props, FALSE);
wp_debug_object (self, "applying rule(%s) for client props", rule);
for (guint i = 0; i < self->rules->len; i++) {
Rule *r = g_ptr_array_index (self->rules, i);
if (g_str_equal (rule, r->rule)) {
for (guint j = 0; j < r->matches->len; j++) {
Match *m = g_ptr_array_index (r->matches, j);
for (guint k = 0; k < m->interests->len; k++) {
WpObjectInterest *interest = g_ptr_array_index (m->interests, k);
wp_debug_object (self, ". working on interest obj(%p)", interest);
if (wp_object_interest_matches (interest, client_props)) {
if (applied_props)
wp_properties_add (applied_props, m->actions);
else
wp_properties_add (client_props, m->actions);
wp_debug_object (self, "match found for rule(%s) with actions"
"(%d)", rule, wp_properties_get_count(m->actions));
return TRUE;
}
}
}
}
}
return FALSE;
}
enum {
STEP_LOAD = WP_TRANSITION_STEP_CUSTOM_START,
};
@ -409,240 +239,6 @@ wp_settings_get_instance (WpCore *core, const gchar *metadata_name)
return settings;
}
static void
match_unref (Match * self)
{
g_clear_pointer (&self->actions, wp_properties_unref);
g_clear_pointer (&self->interests, g_ptr_array_unref);
g_slice_free (Match, self);
}
static WpProperties *
parse_actions (const gchar *actions)
{
g_autoptr (WpSpaJson) o = wp_spa_json_new_from_string (actions);
g_autofree gchar *update_props = NULL;
g_autoptr (WpProperties) a_props = wp_properties_new_empty ();
wp_debug(".. parsing actions");
if (!o || !wp_spa_json_is_object (o)) {
wp_warning ("malformated JSON: actions has to be an object JSON element"
", skip processing this one");
return NULL;
}
if (wp_spa_json_object_get (o,
"update-props", "s", &update_props,
NULL)) {
g_autoptr (WpSpaJson) json = wp_spa_json_new_from_string (update_props);
g_autoptr (WpIterator) iter = wp_spa_json_new_iterator (json);
g_auto (GValue) item = G_VALUE_INIT;
wp_debug (".. update-props=%s", update_props);
while (wp_iterator_next (iter, &item)) {
WpSpaJson *p = g_value_get_boxed (&item);
g_autofree gchar *prop = wp_spa_json_parse_string (p);
g_autofree gchar *value = NULL;
g_value_unset (&item);
if (!wp_iterator_next (iter, &item))
break;
p = g_value_get_boxed (&item);
value = wp_spa_json_parse_string (p);
g_value_unset (&item);
if (prop && value) {
wp_debug (".. prop=%s value=%s", prop, value);
wp_properties_set (a_props, prop, value);
}
}
} else {
return NULL;
}
return g_steal_pointer (&a_props);
}
static Match *
parse_matches (const gchar *match)
{
g_autoptr (WpSpaJson) a = wp_spa_json_new_from_string (match);
g_autoptr (WpIterator) a_iter = wp_spa_json_new_iterator (a);
g_auto (GValue) a_item = G_VALUE_INIT;
Match *m = g_slice_new0 (Match);
g_return_val_if_fail (m, NULL);
wp_debug(".. parsing match");
m->interests = g_ptr_array_new_with_free_func
((GDestroyNotify) wp_object_interest_unref);
if (!wp_spa_json_is_array (a)) {
wp_warning ("malformated JSON: matches has to be an array JSON element"
", skip processing this one");
return NULL;
}
for (; wp_iterator_next (a_iter, &a_item); g_value_unset (&a_item)) {
g_autoptr (WpObjectInterest) i = wp_object_interest_new_type
(WP_TYPE_PROPERTIES);
WpSpaJson *o = g_value_get_boxed (&a_item);
g_autoptr (WpIterator) o_iter = wp_spa_json_new_iterator (o);
g_auto (GValue) o_item = G_VALUE_INIT;
int count = 0;
while (wp_iterator_next (o_iter, &o_item)) {
WpSpaJson *p = g_value_get_boxed (&o_item);
if (wp_spa_json_is_container (p)) {
wp_warning ("malformated JSON: misplaced container object, pls check"
" JSON formatting of .conf file, skipping this container");
continue;
}
g_autofree gchar *isubject = wp_spa_json_parse_string (p);
g_autofree gchar *value = NULL;
gchar *ivalue = NULL;
WpConstraintVerb iverb = WP_CONSTRAINT_VERB_EQUALS;
g_value_unset (&o_item);
if (!wp_iterator_next (o_iter, &o_item))
break;
p = g_value_get_boxed (&o_item);
ivalue = value = wp_spa_json_parse_string (p);
g_value_unset (&o_item);
if (value[0] == '~') {
iverb = WP_CONSTRAINT_VERB_MATCHES;
ivalue = value+1;
}
if (isubject && ivalue) {
wp_object_interest_add_constraint (i, WP_CONSTRAINT_TYPE_PW_PROPERTY,
isubject, iverb, g_variant_new_string(ivalue));
count++;
wp_debug (".. subject=%s verb=%d value=%s of interest obj=%p",
isubject, iverb, ivalue, i);
}
}
wp_debug (".. loaded interest obj(%p) with (%d) constraints", i, count);
g_ptr_array_add (m->interests, g_steal_pointer(&i));
}
return m;
}
static Rule *
parse_rule (const gchar *rule, const gchar *value)
{
g_autoptr (WpSpaJson) json = wp_spa_json_new_from_string (value);
g_autoptr (WpIterator) iter = wp_spa_json_new_iterator (json);
g_auto (GValue) item = G_VALUE_INIT;
Rule *r = g_slice_new0 (Rule);
g_return_val_if_fail (r, NULL);
r->rule = g_strdup (rule);
wp_debug (". parsing rule(%s)", r->rule);
r->matches = g_ptr_array_new_with_free_func
((GDestroyNotify) match_unref);
for (; wp_iterator_next (iter, &item); g_value_unset (&item)) {
WpSpaJson *o = g_value_get_boxed (&item);
g_autofree gchar *match = NULL;
g_autofree gchar *actions = NULL;
Match *m = NULL;
if (!o || !wp_spa_json_is_object (o)) {
wp_warning ("malformated JSON: rule has to be an object JSON element"
", skip processing this one");
continue;
}
if (!wp_spa_json_object_get (o,
"matches", "s", &match,
"actions", "s", &actions,
NULL))
continue;
m = parse_matches (match);
g_ptr_array_add (r->matches, m);
wp_debug (". loaded (%d) interest objects for this match for rule(%s)",
m->interests->len, r->rule);
m->actions = parse_actions (actions);
wp_debug (". loaded (%d) actions for this match for rule(%s)",
wp_properties_get_count (m->actions), r->rule);
}
return r;
}
static gboolean
is_rule (WpSpaJson *json)
{
/* rule is an array and starts with an object */
if (wp_spa_json_is_array (json)) {
g_autoptr (WpIterator) iter = wp_spa_json_new_iterator (json);
g_auto (GValue) item = G_VALUE_INIT;
if (wp_iterator_next (iter, &item)) {
WpSpaJson *o = g_value_get_boxed (&item);
if (o && wp_spa_json_is_object (o))
return TRUE;
}
}
return FALSE;
}
static Rule *
find_rule (WpSettings *self, const gchar *name)
{
for (guint i = 0; i < self->rules->len; i++) {
Rule *r = g_ptr_array_index (self->rules, i);
if (g_str_equal (r->rule, name))
return r;
}
return NULL;
}
static void
rule_unref (Rule * self)
{
g_clear_pointer (&self->rule, g_free);
g_clear_pointer (&self->matches, g_ptr_array_unref);
g_slice_free (Rule, self);
}
static void
parse_setting (const gchar *setting, const gchar *value, WpSettings *self)
{
g_autoptr (WpSpaJson) json = wp_spa_json_new_from_string (value);
if (is_rule (json)) {
Rule *r = find_rule (self, setting);
if (r) {
/* append new matches to existing rule */
Rule *new_r = parse_rule (setting, value);
if (new_r) {
for (guint i = 0; i < new_r->matches->len; i++) {
Match *m = g_ptr_array_index (new_r->matches, i);
g_ptr_array_add (r->matches, m);
}
rule_unref (new_r);
}
} else {
r = parse_rule (setting, value);
g_ptr_array_add (self->rules, r);
}
wp_debug_object (self, "added (%d) matches for rule (%s)", r->matches->len,
r->rule);
} else {
wp_properties_set (self->settings, setting, value);
}
}
static void
on_metadata_changed (WpMetadata *m, guint32 subject,
const gchar *setting, const gchar *type, const gchar *new_value, gpointer d)
@ -704,16 +300,15 @@ on_metadata_added (WpObjectManager *om, WpMetadata *m, gpointer d)
g_signal_connect_object (m, "changed", G_CALLBACK (on_metadata_changed),
self, 0);
/* traverse through all settings and rules */
/* traverse through all settings */
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
const gchar *setting, *value;
wp_metadata_iterator_item_extract (&val, NULL, &setting, NULL, &value);
parse_setting (setting, value, self);
wp_properties_set (self->settings, setting, value);
}
wp_info_object (self, "loaded %d settings and %d rules from metadata \"%s\"",
wp_info_object (self, "loaded %d settings and from metadata \"%s\"",
wp_properties_get_count (self->settings),
self->rules->len,
self->metadata_name);
wp_object_update_features (WP_OBJECT (self), WP_SETTINGS_LOADED, 0);
@ -739,8 +334,6 @@ wp_settings_activate_execute_step (WpObject * object,
case STEP_LOAD: {
self->settings = wp_properties_new_empty ();
self->rules = g_ptr_array_new_with_free_func ((GDestroyNotify) rule_unref);
self->callbacks = g_ptr_array_new_with_free_func
((GDestroyNotify) callback_unref);
@ -773,7 +366,6 @@ wp_settings_deactivate (WpObject * object, WpObjectFeatures features)
wp_debug_object (self, "%s", self->metadata_name);
g_free (self->metadata_name);
g_clear_object (&self->metadata_om);
g_clear_pointer (&self->rules, g_ptr_array_unref);
g_clear_pointer (&self->callbacks, g_ptr_array_unref);
g_clear_pointer (&self->settings, wp_properties_unref);

View file

@ -64,26 +64,6 @@ gboolean wp_settings_unsubscribe (WpSettings *self,
WP_API
WpSpaJson * wp_settings_get (WpSettings *self, const gchar *setting);
WP_API
gboolean wp_settings_parse_boolean_safe (WpSettings *self, const gchar *setting,
gboolean value);
WP_API
gint wp_settings_parse_int_safe (WpSettings *self, const gchar *setting,
gint value);
WP_API
float wp_settings_parse_float_safe (WpSettings *self, const gchar *setting,
float value);
WP_API
gchar * wp_settings_parse_string_safe (WpSettings *self, const gchar *setting,
const gchar *value);
WP_API
gboolean wp_settings_apply_rule (WpSettings *self, const gchar *rule,
WpProperties *client_props, WpProperties *applied_props);
G_END_DECLS
#endif

View file

@ -1659,157 +1659,6 @@ settings_get (lua_State *L)
return 1;
}
static int
settings_parse_boolean_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const gboolean v = lua_toboolean (L, 2) ? TRUE : FALSE;
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
if (s)
lua_pushboolean (L, wp_settings_parse_boolean_safe (s, setting, v));
else
lua_pushboolean (L, v);
return 1;
}
static int
settings_parse_int_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const gint v = luaL_checkinteger (L, 2);
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
if (s)
lua_pushinteger (L, wp_settings_parse_int_safe (s, setting, v));
else
lua_pushinteger (L, v);
return 1;
}
static int
settings_parse_float_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const float v = lua_tonumber (L, 2);
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
if (s)
lua_pushnumber (L, wp_settings_parse_float_safe (s, setting, v));
else
lua_pushnumber (L, v);
return 1;
}
static int
settings_parse_string_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const char *v = luaL_checkstring (L, 2);
g_autofree gchar *res = NULL;
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
res = s ? wp_settings_parse_string_safe (s, setting, v) : g_strdup (v);
lua_pushstring (L, res);
return 1;
}
static int
settings_parse_array_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
g_autoptr (WpSpaJson) json_default = NULL;
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
if (lua_isuserdata (L, 2)) {
WpSpaJson *v = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
if (v && wp_spa_json_is_array (v))
json_default = wp_spa_json_ref (v);
}
if (!json_default) {
wp_warning ("Using empty array for setting '%s' as fallback value isn't "
"a JSON array", setting);
json_default = wp_spa_json_new_array (NULL, NULL);
}
if (s) {
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
if (j) {
if (wp_spa_json_is_array (j)) {
push_luajson (L, j);
return 1;
} else {
wp_warning ("Ignoring setting '%s' as it isn't a JSON array", setting);
}
}
}
push_luajson (L, json_default);
return 1;
}
static int
settings_parse_object_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
g_autoptr (WpSpaJson) json_default = NULL;
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
if (lua_isuserdata (L, 2)) {
WpSpaJson *v = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
if (v && wp_spa_json_is_object (v))
json_default = wp_spa_json_ref (v);
}
if (!json_default) {
wp_warning ("Using empty object for setting '%s' as fallback value isn't "
"a JSON object", setting);
json_default = wp_spa_json_new_array (NULL, NULL);
}
if (s) {
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
if (j) {
if (wp_spa_json_is_object (j)) {
push_luajson (L, j);
return 1;
} else {
wp_warning ("Ignoring setting '%s' as it isn't a JSON object", setting);
}
}
}
push_luajson (L, json_default);
return 1;
}
static int
settings_apply_rule (lua_State *L)
{
const char *r = luaL_checkstring (L, 1);
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L),
"sm-settings");
g_autoptr (WpProperties) cp = wplua_table_to_properties (L, 2);
g_autoptr (WpProperties) ap = wp_properties_new_empty ();
if (s) {
gboolean value = wp_settings_apply_rule (s, r, cp, ap);
lua_pushboolean (L, value);
wplua_properties_to_table (L, ap);
return 2;
}
lua_pushnil (L);
return 1;
}
static int
settings_subscribe (lua_State *L)
{
@ -1828,7 +1677,6 @@ settings_subscribe (lua_State *L)
return 1;
}
static int
settings_unsubscribe (lua_State *L)
{
@ -1846,13 +1694,6 @@ settings_unsubscribe (lua_State *L)
static const luaL_Reg settings_methods[] = {
{ "get", settings_get },
{ "parse_boolean_safe", settings_parse_boolean_safe },
{ "parse_int_safe", settings_parse_int_safe },
{ "parse_float_safe", settings_parse_float_safe },
{ "parse_string_safe", settings_parse_string_safe },
{ "parse_array_safe", settings_parse_array_safe },
{ "parse_object_safe", settings_parse_object_safe },
{ "apply_rule", settings_apply_rule },
{ "subscribe", settings_subscribe },
{ "unsubscribe", settings_unsubscribe },
{ NULL, NULL }

View file

@ -3,46 +3,41 @@
wireplumber.settings = {
## Enables flatpak portal
# access-enable-flatpak-portal = true
## The list of access rules
access.rules = [
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# pipewire.access = "flatpak"
# media.category = "Manager"
# }
# ]
# actions = {
# update-props = {
# default_permissions = "all",
# }
# }
# }
# {
# matches = [
# {
# pipewire.access = "flatpak"
# }
# ]
# actions = {
# update-props = {
# default_permissions = "rx"
# }
# }
# }
# {
# matches = [
# {
# pipewire.access = "restricted"
# }
# ]
# actions = {
# update-props = {
# default_permissions = "rx"
# }
# }
# }
]
}
access.rules = [
## The list of access rules
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# pipewire.access = "flatpak"
# media.category = "Manager"
# }
# ]
# update-props = {
# default_permissions = "all",
# }
# }
# {
# matches = [
# {
# pipewire.access = "flatpak"
# }
# ]
# update-props = {
# default_permissions = "rx"
# }
# }
# {
# matches = [
# {
# pipewire.access = "restricted"
# }
# ]
# update-props = {
# default_permissions = "rx"
# }
# }
]

View file

@ -21,153 +21,152 @@ wireplumber.settings = {
## not used by the session manager, in order to be able to
## connect to the real JACK server.
# monitor.alsa.jack-device = false
}
monitor.alsa.properties = {
## The properties used when constructing the 'api.alsa.enum.udev' plugin
# monitor.alsa.properties = {}
}
monitor.alsa.midi.node-properties = {
## MIDI bridge node properties
## Name set for the node with ALSA MIDI ports
node.name = "Midi-Bridge"
## Removes longname/number from MIDI port names
api.alsa.disable-longname = true
}
monitor.alsa.vm.node.defaults = {
## These properties override node defaults when running in a virtual machine.
## The rules below still override those.
# monitor.alsa.vm.node.defaults = {
# api.alsa.period-size = 256
# api.alsa.headroom = 8192
# }
## MIDI bridge node properties
# monitor.alsa.midi.node-properties = {
# ## Name set for the node with ALSA MIDI ports
# node.name = "Midi-Bridge"
# ## Removes longname/number from MIDI port names
# api.alsa.disable-longname = true
# }
## The list of monitor rules
monitor.alsa.rules = [
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# device.name = "~alsa_card.*"
# }
# ]
# actions = {
# update-props = {
# api.alsa.use-acp = true
# api.acp.auto-port = false
# }
# }
# }
## This rule example allows changing properties on all ALSA devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~alsa_card.*"
# }
# ]
# actions = {
# update-props = {
# ## Use ALSA-Card-Profile devices. They use UCM or the profile
# ## configuration to configure the device and mixer settings.
# api.alsa.use-acp = false
#
# ## Use UCM instead of profile when available. Can be
# ## disabled to skip trying to use the UCM profile.
# api.alsa.use-ucm = false
#
# ## Don't use the hardware mixer for volume control. It
# ## will only use software volume. The mixer is still used
# ## to mute unused paths based on the selected port.
# api.alsa.soft-mixer = false
#
# ## Ignore decibel settings of the driver. Can be used to
# ## work around buggy drivers that report wrong values.
# api.alsa.ignore-dB = false
#
# ## The profile set to use for the device. Usually this is
# ## "default.conf" but can be changed with a udev rule or here.
# device.profile-set = "profileset-name"
#
# ## The default active profile. Is by default set to "Off".
# device.profile = "default profile name"
#
# ## Automatically select the best profile. This is the
# ## highest priority available profile. This is disabled
# ## here and instead implemented in the session manager
# ## where it can save and load previous preferences.
# api.acp.auto-profile = false
#
# ## Automatically switch to the highest priority available port.
# ## This is disabled here and implemented in the session manager instead.
# api.acp.auto-port = true
#
# ## Other properties can be set here.
# device.nick = "My Device"
#
# ## Whether to disable the device or not
# device.disabled = false
# }
# }
# }
## This rule example allows changing properties on all ALSA nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~alsa_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~alsa_output.*"
# }
# ]
# actions = {
# update-props = {
# node.nick = "My Node"
# node.description = "My Node Description"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# monitor.channel-volumes = false
# resample.quality = 4
# resample.disable = false
# channelmix.normalize = false
# channelmix.mix-lfe = false
# channelmix.upmix = true
#
# ## only "psd", "none" or "simple" values are accepted
# channelmix.upmix-method = "psd"
#
# channelmix.lfe-cutoff = 150
# channelmix.fc-cutoff = 12000
# channelmix.rear-delay = 12.0
# channelmix.stereo-widen = 0.0
# channelmix.hilbert-taps = 0
# channelmix.disable = false
# dither.noise = 0
# dither.method = "none"
# audio.channels = 2
# audio.format = "S16LE"
# audio.rate = 44100
# audio.allowed-rates = "32000,96000"
# audio.position = "FLFR"
# api.alsa.period-size = 1024
# api.alsa.period-num = 2
# api.alsa.headroom = 0
# api.alsa.start-delay = 0
# api.alsa.disable-mmap = false
# api.alsa.disable-batch = false
# api.alsa.use-chmap = false
# api.alsa.multirate = true
# latency.internal.rate = 0
# latency.internal.ns = 0
# clock.name = "api.alsa.0"
#
# ## 0 disables suspend
# session.suspend-timeout-seconds = 5
# }
# }
# }
]
api.alsa.period-size = 256
api.alsa.headroom = 8192
}
monitor.alsa.rules = [
## The list of monitor rules
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# device.name = "~alsa_card.*"
# }
# ]
# update-props = {
# api.alsa.use-acp = true
# api.acp.auto-port = false
# }
# }
## This rule example allows changing properties on all ALSA devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~alsa_card.*"
# }
# ]
# update-props = {
# ## Use ALSA-Card-Profile devices. They use UCM or the profile
# ## configuration to configure the device and mixer settings.
# api.alsa.use-acp = false
#
# ## Use UCM instead of profile when available. Can be
# ## disabled to skip trying to use the UCM profile.
# api.alsa.use-ucm = false
#
# ## Don't use the hardware mixer for volume control. It
# ## will only use software volume. The mixer is still used
# ## to mute unused paths based on the selected port.
# api.alsa.soft-mixer = false
#
# ## Ignore decibel settings of the driver. Can be used to
# ## work around buggy drivers that report wrong values.
# api.alsa.ignore-dB = false
#
# ## The profile set to use for the device. Usually this is
# ## "default.conf" but can be changed with a udev rule or here.
# device.profile-set = "profileset-name"
#
# ## The default active profile. Is by default set to "Off".
# device.profile = "default profile name"
#
# ## Automatically select the best profile. This is the
# ## highest priority available profile. This is disabled
# ## here and instead implemented in the session manager
# ## where it can save and load previous preferences.
# api.acp.auto-profile = false
#
# ## Automatically switch to the highest priority available port.
# ## This is disabled here and implemented in the session manager instead.
# api.acp.auto-port = true
#
# ## Other properties can be set here.
# device.nick = "My Device"
#
# ## Whether to disable the device or not
# device.disabled = false
# }
# }
## This rule example allows changing properties on all ALSA nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~alsa_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~alsa_output.*"
# }
# ]
# update-props = {
# node.nick = "My Node"
# node.description = "My Node Description"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# monitor.channel-volumes = false
# resample.quality = 4
# resample.disable = false
# channelmix.normalize = false
# channelmix.mix-lfe = false
# channelmix.upmix = true
#
# ## only "psd", "none" or "simple" values are accepted
# channelmix.upmix-method = "psd"
#
# channelmix.lfe-cutoff = 150
# channelmix.fc-cutoff = 12000
# channelmix.rear-delay = 12.0
# channelmix.stereo-widen = 0.0
# channelmix.hilbert-taps = 0
# channelmix.disable = false
# dither.noise = 0
# dither.method = "none"
# audio.channels = 2
# audio.format = "S16LE"
# audio.rate = 44100
# audio.allowed-rates = "32000,96000"
# audio.position = "FLFR"
# api.alsa.period-size = 1024
# api.alsa.period-num = 2
# api.alsa.headroom = 0
# api.alsa.start-delay = 0
# api.alsa.disable-mmap = false
# api.alsa.disable-batch = false
# api.alsa.use-chmap = false
# api.alsa.multirate = true
# latency.internal.rate = 0
# latency.internal.ns = 0
# clock.name = "api.alsa.0"
#
# ## 0 disables suspend
# session.suspend-timeout-seconds = 5
# }
# }
]

View file

@ -8,186 +8,187 @@ wireplumber.settings = {
## This requires access to the D-Bus user session; disable if you are running
## a system-wide instance of wireplumber.
# monitor.bluetooth.enable-logind = true
}
monitor.bluetooth.properties = {
## The properties used when constructing the 'api.bluez5.enum.dbus' plugin
# monitor.bluetooth.properties = {
# ## Whether to support connection info or not
# api.bluez5.connection-info = true
# ## These features do not work on all headsets, so they are enabled
# ## by default based on the hardware database. They can also be
# ## forced on/off for all devices by the following options:
# bluez5.enable-sbc-xq = true
# bluez5.enable-msbc = true
# bluez5.enable-hw-volume = true
## Whether to support connection info or not
api.bluez5.connection-info = true
# ## Enabled roles (default: [ a2dp_sink a2dp_source bap_sink bap_source hfp_hf hfp_ag ])
# ##
# ## Currently some headsets (Sony WH-1000XM3) are not working with
# ## both hsp_ag and hfp_ag enabled, so by default we enable only HFP.
# ##
# ## Supported roles: hsp_hs (HSP Headset),
# ## hsp_ag (HSP Audio Gateway),
# ## hfp_hf (HFP Hands-Free),
# ## hfp_ag (HFP Audio Gateway)
# ## a2dp_sink (A2DP Audio Sink)
# ## a2dp_source (A2DP Audio Source)
# ## bap_sink (LE Audio Basic Audio Profile Sink)
# ## bap_source (LE Audio Basic Audio Profile Source)
# # bluez5.roles = "[ a2dp_sink a2dp_source bap_sink bap_source hsp_hs hsp_ag hfp_hf hfp_ag ]"
## Enabled roles (default: [ a2dp_sink a2dp_source bap_sink bap_source hfp_hf hfp_ag ])
##
## Currently some headsets (Sony WH-1000XM3) are not working with
## both hsp_ag and hfp_ag enabled, so by default we enable only HFP.
##
## Supported roles: hsp_hs (HSP Headset),
## hsp_ag (HSP Audio Gateway),
## hfp_hf (HFP Hands-Free),
## hfp_ag (HFP Audio Gateway)
## a2dp_sink (A2DP Audio Sink)
## a2dp_source (A2DP Audio Source)
## bap_sink (LE Audio Basic Audio Profile Sink)
## bap_source (LE Audio Basic Audio Profile Source)
# bluez5.roles = "[ a2dp_sink a2dp_source bap_sink bap_source hsp_hs hsp_ag hfp_hf hfp_ag ]"
# ## Enabled A2DP codecs (default: all).
# bluez5.codecs = "[ sbc sbc_xq aac ldac aptx aptx_hd aptx_ll aptx_ll_duplex faststream faststream_duplex ]"
## Enabled A2DP codecs (default: all).
# bluez5.codecs = "[ sbc sbc_xq aac ldac aptx aptx_hd aptx_ll aptx_ll_duplex faststream faststream_duplex ]"
# ## HFP/HSP backend (default: native).
# ## Available values: any, none, hsphfpd, ofono, native
# bluez5.hfphsp-backend = "native"
## These features do not work on all headsets, so they are enabled
## by default based on the hardware database. They can also be
## forced on/off for all devices by the following options:
# bluez5.enable-sbc-xq = true
# bluez5.enable-msbc = true
# bluez5.enable-hw-volume = true
# ## HFP/HSP native backend modem (default: none).
# ## Available values: none, any or the modem device string as found in
# ## 'Device' property of org.freedesktop.ModemManager1.Modem interface
# bluez5.hfphsp-backend-native-modem = "none"
## HFP/HSP backend (default: native).
## Available values: any, none, hsphfpd, ofono, native
# bluez5.hfphsp-backend = "native"
# ## HFP/HSP hardware offload SCO support (default: false).
# bluez5.hw-offload-sco = false
## HFP/HSP native backend modem (default: none).
## Available values: none, any or the modem device string as found in
## 'Device' property of org.freedesktop.ModemManager1.Modem interface
# bluez5.hfphsp-backend-native-modem = "none"
# ## Properties for the A2DP codec configuration
# bluez5.default.rate = 48000
# bluez5.default.channels = 2
## HFP/HSP hardware offload SCO support (default: false).
# bluez5.hw-offload-sco = false
# ## Register dummy AVRCP player, required for AVRCP volume function.
# ## Disable if you are running mpris-proxy or equivalent.
# bluez5.dummy-avrcp-player = true
## Properties for the A2DP codec configuration
# bluez5.default.rate = 48000
# bluez5.default.channels = 2
# ## Opus Pro Audio mode settings
# bluez5.a2dp.opus.pro.channels = 3
# bluez5.a2dp.opus.pro.coupled-streams = 1
# bluez5.a2dp.opus.pro.locations = "FL,FR,LFE"
# bluez5.a2dp.opus.pro.max-bitrate = 600000
# bluez5.a2dp.opus.pro.frame-dms = 50
# bluez5.a2dp.opus.pro.bidi.channels = 1
# bluez5.a2dp.opus.pro.bidi.coupled-streams = 0
# bluez5.a2dp.opus.pro.bidi.locations = "FC"
# bluez5.a2dp.opus.pro.bidi.max-bitrate = 160000
# bluez5.a2dp.opus.pro.bidi.frame-dms = 400
# }
## Register dummy AVRCP player, required for AVRCP volume function.
## Disable if you are running mpris-proxy or equivalent.
# bluez5.dummy-avrcp-player = true
## Opus Pro Audio mode settings
# bluez5.a2dp.opus.pro.channels = 3
# bluez5.a2dp.opus.pro.coupled-streams = 1
# bluez5.a2dp.opus.pro.locations = "FL,FR,LFE"
# bluez5.a2dp.opus.pro.max-bitrate = 600000
# bluez5.a2dp.opus.pro.frame-dms = 50
# bluez5.a2dp.opus.pro.bidi.channels = 1
# bluez5.a2dp.opus.pro.bidi.coupled-streams = 0
# bluez5.a2dp.opus.pro.bidi.locations = "FC"
# bluez5.a2dp.opus.pro.bidi.max-bitrate = 160000
# bluez5.a2dp.opus.pro.bidi.frame-dms = 400
}
monitor.bluetooth-midi.properties = {
## The properties used when constructing the 'api.bluez5.midi.enum' plugin
monitor.bluetooth-midi.properties = {}
}
monitor.bluetooth-midi.servers = [
## List of MIDI server node names. Each node name given will create a new instance
## of a BLE MIDI service. Typical BLE MIDI instruments have on service instance,
## so adding more than one here may confuse some clients. The node property matching
## rules below apply also to these servers.
monitor.bluetooth-midi.servers = [ "bluez_midi.server" ]
"bluez_midi.server"
]
monitor.bluetooth.rules = [
## The list of monitor rules
monitor.bluetooth = [
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# device.name = "~bluez_card.*"
# }
# ]
# actions = {
# update-props = {
# bluez5.auto-connect = "[ hfp_hf hsp_hs a2dp_sink ]"
# }
# }
# }
## This rule example allows changing properties on all Bluetooth devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~bluez_card.*"
# }
# ]
# actions = {
# update-props = {
# ## Auto-connect device profiles on start up or when only partial
# ## profiles have connected. Disabled by default if the property
# ## is not specified.
# bluez5.auto-connect = "[ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]"
#
# ## Hardware volume control (default: [ hfp_ag hsp_ag a2dp_source ])
# bluez5.hw-volume = "[ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]"
#
# ## LDAC encoding quality
# ## Available values: auto (Adaptive Bitrate, default)
# ## hq (High Quality, 990/909kbps)
# ## sq (Standard Quality, 660/606kbps)
# ## mq (Mobile use Quality, 330/303kbps)
# bluez5.a2dp.ldac.quality = "auto"
#
# ## AAC variable bitrate mode
# ## Available values: 0 (cbr, default), 1-5 (quality level)
# bluez5.a2dp.aac.bitratemode = 0
#
# ## Profile connected first
# ## Available values: a2dp-sink (default), headset-head-unit
# device.profile = "a2dp-sink"
#
# ## Opus Pro Audio encoding mode: audio, voip, lowdelay
# bluez5.a2dp.opus.pro.application = "audio"
# bluez5.a2dp.opus.pro.bidi.application = "audio"
# }
# }
# }
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# device.name = "~bluez_card.*"
# }
# ]
# update-props = {
# bluez5.auto-connect = "[ hfp_hf hsp_hs a2dp_sink ]"
# }
# }
## This rule example allows changing properties on all Bluetooth nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~bluez_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~bluez_output.*"
# }
# ]
# actions = {
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# resample.quality = 4
# channelmix.normalize = false
# channelmix.mix-lfe = false
# session.suspend-timeout-seconds = 5
# monitor.channel-volumes = false
#
# ## Media source role, "input" or "playback"
# ## Defaults to "playback", playing stream to speakers
# ## Set to "input" to use as an input for apps
# bluez5.media-source-role = "input"
# }
# }
# }
]
## This rule example allows changing properties on all Bluetooth devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~bluez_card.*"
# }
# ]
# update-props = {
# ## Auto-connect device profiles on start up or when only partial
# ## profiles have connected. Disabled by default if the property
# ## is not specified.
# bluez5.auto-connect = "[ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]"
#
# ## Hardware volume control (default: [ hfp_ag hsp_ag a2dp_source ])
# bluez5.hw-volume = "[ hfp_hf hsp_hs a2dp_sink hfp_ag hsp_ag a2dp_source ]"
#
# ## LDAC encoding quality
# ## Available values: auto (Adaptive Bitrate, default)
# ## hq (High Quality, 990/909kbps)
# ## sq (Standard Quality, 660/606kbps)
# ## mq (Mobile use Quality, 330/303kbps)
# bluez5.a2dp.ldac.quality = "auto"
#
# ## AAC variable bitrate mode
# ## Available values: 0 (cbr, default), 1-5 (quality level)
# bluez5.a2dp.aac.bitratemode = 0
#
# ## Profile connected first
# ## Available values: a2dp-sink (default), headset-head-unit
# device.profile = "a2dp-sink"
#
# ## Opus Pro Audio encoding mode: audio, voip, lowdelay
# bluez5.a2dp.opus.pro.application = "audio"
# bluez5.a2dp.opus.pro.bidi.application = "audio"
# }
# }
## This rule example allows changing properties on all Bluetooth nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~bluez_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~bluez_output.*"
# }
# ]
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# resample.quality = 4
# channelmix.normalize = false
# channelmix.mix-lfe = false
# session.suspend-timeout-seconds = 5
# monitor.channel-volumes = false
#
# ## Media source role, "input" or "playback"
# ## Defaults to "playback", playing stream to speakers
# ## Set to "input" to use as an input for apps
# bluez5.media-source-role = "input"
# }
# }
]
monitor.bluetooth-midi.rules = [
## The list of monitor MIDI rules
monitor.bluetooth-midi = [
## This rule example allows changing properties on all Bluetooth MIDI nodes.
# {
# matches = {
# {
# ## Matches all nodes.
# { "node.name", "matches", "bluez_midi.*" },
# },
# },
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# session.suspend-timeout-seconds = 5
# monitor.channel-volumes = false
# }
# }
]
}
## This rule example allows changing properties on all Bluetooth MIDI nodes.
# {
# matches = {
# {
# ## Matches all nodes.
# { "node.name", "matches", "bluez_midi.*" },
# },
# },
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# session.suspend-timeout-seconds = 5
# monitor.channel-volumes = false
# }
# }
]

View file

@ -23,24 +23,4 @@ wireplumber.settings = {
## Sets the default echo-cancel-source node name to automatically switch to
# device.echo-cancel-source-name = "echo-cancel-source"
## Sets persistent device profiles that should never be changed, when
## wireplumber is running, even if a new profile with higher priority becomes
## available
device.rules = [
## The following are the default rules applied if none overrides them.
# {
# matches = [
# {
# ## Matches all devices
# device.name = "~*"
# }
# ]
# actions = {
# update-props = {
# persistent_profile_names = "off pro-audio"
# }
# }
# }
]
}

View file

@ -1,95 +1,95 @@
## The WirePlumber endpoint configuration
wireplumber.settings = {
endpoints = {
## The list of endpoints to create
endpoints = {
# endpoint.capture = {
# media.class = "Audio/Source"
# role = "Capture"
# }
# endpoint.multimedia = {
# media.class = "Audio/Sink"
# role = "Multimedia"
# }
# endpoint.speech_low = {
# media.class = "Audio/Sink"
# role = "Speech-Low"
# }
# endpoint.custom_low = {
# media.class = "Audio/Sink"
# role = "Custom-Low"
# }
# endpoint.navigation = {
# media.class = "Audio/Sink"
# role = "Navigation"
# }
# endpoint.speech_high = {
# media.class = "Audio/Sink"
# role = "Speech-High"
# }
# endpoint.custom_high = {
# media.class = "Audio/Sink"
# role = "Custom-High"
# }
# endpoint.communication = {
# media.class = "Audio/Sink"
# role = "Communication"
# }
# endpoint.emergency = {
# media.class = "Audio/Sink"
# role = "Emergency"
# }
}
## The list of endpoint roles to use
endpoints-roles = {
# Capture = {
# alias = [ "Multimedia", "Music", "Voice", "Capture" ]
# priority = 25
# action.default = "cork"
# action.capture = "mix"
# media.class = "Audio/Source"
# }
# Multimedia = {
# alias = [ "Movie" "Music" "Game" ]
# priority = 25
# action.default = "cork"
# }
# Speech-Low = {
# priority = 30
# action.default = "cork"
# action.Speech-Low = "mix"
# }
# Custom-Low = {
# priority = 35
# action.default = "cork"
# action.Custom-Low = "mix"
# }
# Navigation = {
# priority = 50
# action.default = "duck"
# action.Navigation = "mix"
# }
# Speech-High = {
# priority = 60
# action.default = "cork"
# action.Speech-High = "mix"
# }
# Custom-High = {
# priority = 65
# action.default = "cork"
# action.Custom-High = "mix"
# }
# Communication = {
# priority = 75
# action.default = "cork"
# action.Communication = "mix"
# }
# Emergency = {
# alias = [ "Alert" ]
# priority = 99
# action.default = "cork"
# action.Emergency = "mix"
# }
}
# endpoint.capture = {
# media.class = "Audio/Source"
# role = "Capture"
# }
# endpoint.multimedia = {
# media.class = "Audio/Sink"
# role = "Multimedia"
# }
# endpoint.speech_low = {
# media.class = "Audio/Sink"
# role = "Speech-Low"
# }
# endpoint.custom_low = {
# media.class = "Audio/Sink"
# role = "Custom-Low"
# }
# endpoint.navigation = {
# media.class = "Audio/Sink"
# role = "Navigation"
# }
# endpoint.speech_high = {
# media.class = "Audio/Sink"
# role = "Speech-High"
# }
# endpoint.custom_high = {
# media.class = "Audio/Sink"
# role = "Custom-High"
# }
# endpoint.communication = {
# media.class = "Audio/Sink"
# role = "Communication"
# }
# endpoint.emergency = {
# media.class = "Audio/Sink"
# role = "Emergency"
# }
}
endpoint-roles = {
## The list of endpoint roles to use
# Capture = {
# alias = [ "Multimedia", "Music", "Voice", "Capture" ]
# priority = 25
# action.default = "cork"
# action.capture = "mix"
# media.class = "Audio/Source"
# }
# Multimedia = {
# alias = [ "Movie" "Music" "Game" ]
# priority = 25
# action.default = "cork"
# }
# Speech-Low = {
# priority = 30
# action.default = "cork"
# action.Speech-Low = "mix"
# }
# Custom-Low = {
# priority = 35
# action.default = "cork"
# action.Custom-Low = "mix"
# }
# Navigation = {
# priority = 50
# action.default = "duck"
# action.Navigation = "mix"
# }
# Speech-High = {
# priority = 60
# action.default = "cork"
# action.Speech-High = "mix"
# }
# Custom-High = {
# priority = 65
# action.default = "cork"
# action.Custom-High = "mix"
# }
# Communication = {
# priority = 75
# action.default = "cork"
# action.Communication = "mix"
# }
# Emergency = {
# alias = [ "Alert" ]
# priority = 99
# action.default = "cork"
# action.Emergency = "mix"
# }
}

View file

@ -3,47 +3,45 @@
wireplumber.settings = {
## Enables libcamera monitor
# monitor.libcamera.enable = true
## The properties used when constructing the 'api.libcamera.enum.manager' plugin
# monitor.libcamera.properties = {}
## The list of monitor rules
monitor.libcamera.rules = [
## This rule example allows changing properties on all libcamera devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~libcamera_device.*"
# }
# ]
# actions = {
# update-props = {
# device.nick = "My Device"
# }
# }
# }
## This rule example allows changing properties on all libcamera nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~libcamera_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~libcamera_output.*"
# }
# ]
# actions = {
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# }
# }
# }
]
}
monitor.libcamera.properties = {
## The properties used when constructing the 'api.libcamera.enum.manager' plugin
}
monitor.libcamera.rules = [
## The list of monitor rules
## This rule example allows changing properties on all libcamera devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~libcamera_device.*"
# }
# ]
# update-props = {
# device.nick = "My Device"
# }
# }
## This rule example allows changing properties on all libcamera nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~libcamera_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~libcamera_output.*"
# }
# ]
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# }
# }
]

View file

@ -30,10 +30,10 @@ wireplumber.settings = {
## Application names correspond to application.name in stream properties.
## Applications which do not set media.role but which should be considered
## for role based profile switching can be specified here.
# policy.bluetooth.media-role.applications = [
# "Firefox", "Chromium input", "Google Chrome input", "Brave input",
# "Microsoft Edge input", "Vivaldi input", "ZOOM VoiceEngine",
# "Telegram Desktop", "telegram-desktop", "linphone", "Mumble",
# "WEBRTC VoiceEngine", "Skype"
# ]
policy.bluetooth.media-role.applications = [
"Firefox", "Chromium input", "Google Chrome input", "Brave input",
"Microsoft Edge input", "Vivaldi input", "ZOOM VoiceEngine",
"Telegram Desktop", "telegram-desktop", "linphone", "Mumble",
"WEBRTC VoiceEngine", "Skype"
]
}

View file

@ -10,22 +10,21 @@ wireplumber.settings = {
## The default channel volume for new streams whose props were never saved
## previously. This is only used if "restore-props" is set to true.
# stream.default-channel-volume = 1.0
## The list of stream rules
stream.rules = [
## This rule example allows setting properties on the "pw-play" stream.
# {
# matches = [
# ## Matches all devices
# { application.name = "pw-play" }
# ]
# actions = {
# update-props = {
# state.restore-props = false
# state.restore-target = false
# state.default-channel-volume = 1.0
# }
# }
# }
]
}
stream.rules = [
## The list of stream rules
## This rule example allows setting properties on the "pw-play" stream.
# {
# matches = [
# ## Matches all devices
# { application.name = "pw-play" }
# ]
# update-props = {
# state.restore-props = false
# state.restore-target = false
# state.default-channel-volume = 1.0
# }
# }
]

View file

@ -1,46 +1,42 @@
## The WirePlumber V4L2 configuration
wireplumber.settings = {
monitor.v4l2.properties = {
## The properties used when constructing the 'api.v4l2.enum.udev' plugin
# monitor.v4l2.properties = {}
## The list of monitor rules
monitor.v4l2.rules = [
## This rule example allows changing properties on all V4L2 devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~v4l2_device.*"
# }
# ]
# actions = {
# update-props = {
# device.nick = "My Device"
# }
# }
# }
## This rule example allows changing properties on all V4L2 nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~v4l2_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~v4l2_output.*"
# }
# ]
# actions = {
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# }
# }
# }
]
}
monitor.v4l2.rules = [
## The list of monitor rules.
## This rule example allows changing properties on all V4L2 devices.
# {
# matches = [
# {
# ## This matches all cards.
# device.name = "~v4l2_device.*"
# }
# ]
# update-props = {
# device.nick = "My Device"
# }
# }
## This rule example allows changing properties on all V4L2 nodes.
# {
# matches = [
# {
# ## Matches all sources.
# node.name = "~v4l2_input.*"
# }
# {
# ## Matches all sinks.
# node.name = "~v4l2_output.*"
# }
# ]
# update-props = {
# node.nick = "My Node"
# priority.driver = 100
# priority.session = 100
# node.pause-on-idle = false
# }
# }
]

View file

@ -19,7 +19,8 @@ function getDefaultPermissions (properties)
end
function getPermissions (properties)
local matched, mprops = Settings.apply_rule ("access.rules", properties)
local matched, mprops = Conf.apply_rules ("access.rules",
properties)
if (matched and mprops["default_permissions"]) then
return mprops["default_permissions"]

View file

@ -51,7 +51,7 @@ cutils.default_metadata_om = ObjectManager {
}
function cutils.evaluateRulesApplyProperties (properties, name)
local matched, mprops = Settings.apply_rule (name, properties)
local matched, mprops = Conf.apply_rules (name, properties)
if (matched and mprops) then
for k, v in pairs (mprops) do

View file

@ -6,14 +6,11 @@
-- SPDX-License-Identifier: MIT
local defaults = {}
defaults.node_properties = Json.Object {
["node.name"] = "Midi-Bridge",
["api.alsa.disable-longname"] = true
}
defaults.node_properties = Json.Object {}
local config = {}
config.node_properties = Settings.parse_object_safe (
"monitor.alsa.midi.node-properties", defaults.node_properties)
config.node_properties = Conf.get_section (
"monitor.alsa.midi.node-properties", defaults.node_properties):parse ()
SND_PATH = "/dev/snd"
SEQ_NAME = "seq"

View file

@ -12,22 +12,19 @@ defaults.reserve_priority = -20
defaults.reserve_application_name = "WirePlumber"
defaults.jack_device = false
defaults.properties = Json.Object {}
defaults.vm_node_defaults = Json.Object {
["api.alsa.period-size"] = 256,
["api.alsa.headroom"] = 8192
}
defaults.vm_node_defaults = Json.Object {}
local config = {}
config.reserve_priority = Settings.parse_int_safe (
config.reserve_priority = Conf.get_value_int ("wireplumber.settings",
"monitor.alsa.reserve-priority", defaults.reserve_priority)
config.reserve_application_name = Settings.parse_string_safe (
config.reserve_application_name = Conf.get_value_string ("wireplumber.settings",
"monitor.alsa.reserve-application-name", defaults.reserve_application_name)
config.jack_device = Settings.parse_boolean_safe (
config.jack_device = Conf.get_value_boolean ("wireplumber.settings",
"monitor.alsa.jack-device", defaults.jack_device)
config.properties = Settings.parse_object_safe (
"monitor.alsa.properties", defaults.properties)
config.vm_node_defaults = Settings.parse_object_safe (
"monitor.alsa.vm.node.defaults", defaults.vm_node_defaults)
config.properties = Conf.get_section (
"monitor.alsa.properties", defaults.properties):parse ()
config.vm_node_defaults = Conf.get_section (
"monitor.alsa.vm.node.defaults", defaults.vm_node_defaults):parse ()
-- unique device/node name tables
device_names_table = nil
@ -270,7 +267,8 @@ function prepareDevice(parent, id, obj_type, factory, properties)
end
-- apply properties from rules defined in JSON .conf file
local applied = cutils.evaluateRulesApplyProperties (properties, "monitor.alsa.rules")
local applied = cutils.evaluateRulesApplyProperties (properties,
"monitor.alsa.rules")
if not applied then
applyDefaultDeviceProperties (properties)
end

View file

@ -12,10 +12,10 @@ defaults.properties = Json.Object {}
defaults.servers = Json.Array { "bluez_midi.server" }
local config = {}
config.properties = Settings.parse_object_safe (
"monitor.bluetooth-midi.properties", defaults.properties)
config.servers = Settings.parse_array_safe (
"monitor.bluetooth-midi.servers", defaults.servers)
config.properties = Conf.get_section (
"monitor.bluetooth-midi.properties", defaults.properties): parse ()
config.servers = Conf.get_section (
"monitor.bluetooth-midi.servers", defaults.servers): parse ()
-- unique device/node name tables
node_names_table = nil
@ -60,7 +60,7 @@ function createNode(parent, id, type, factory, properties)
properties["api.glib.mainloop"] = "true"
-- apply properties from bluetooth.conf
cutils.evaluateRulesApplyProperties (properties, "monitor.bluetooth-midi")
cutils.evaluateRulesApplyProperties (properties, "monitor.bluetooth-midi.rules")
local latency_offset = properties["node.latency-offset-msec"]
properties["node.latency-offset-msec"] = nil
@ -116,7 +116,7 @@ function createServers()
["factory.name"] = "api.bluez5.midi.node",
["api.glib.mainloop"] = "true",
}
cutils.evaluateRulesApplyProperties (node_props, "monitor.bluetooth-midi")
cutils.evaluateRulesApplyProperties (node_props, "monitor.bluetooth-midi.rules")
local latency_offset = node_props["node.latency-offset-msec"]
node_props["node.latency-offset-msec"] = nil

View file

@ -10,13 +10,11 @@ local COMBINE_OFFSET = 64
local cutils = require ("common-utils")
local defaults = {}
defaults.properties = Json.Object {
["api.bluez5.connection-info"] = true
}
defaults.properties = Json.Object {}
local config = {}
config.properties = Settings.parse_object_safe (
"monitor.bluetooth.properties", defaults.properties)
config.properties = Conf.get_section (
"monitor.bluetooth.properties", defaults.properties): parse ()
devices_om = ObjectManager {
Interest {
@ -282,7 +280,7 @@ function createNode(parent, id, type, factory, properties)
end
-- apply properties from bluetooth.conf
cutils.evaluateRulesApplyProperties (properties, "monitor.bluetooth")
cutils.evaluateRulesApplyProperties (properties, "monitor.bluetooth.rules")
-- create the node; bluez requires "local" nodes, i.e. ones that run in
-- the same process as the spa device, for several reasons
@ -344,7 +342,8 @@ function createDevice(parent, id, type, factory, properties)
properties["api.bluez5.id"] = id
-- apply properties from bluetooth.conf
local applied = cutils.evaluateRulesApplyProperties (properties, "monitor.bluetooth")
local applied = cutils.evaluateRulesApplyProperties (properties,
"monitor.bluetooth.rules")
if not applied then
applyDefaultDeviceProperties (properties)
end

View file

@ -11,8 +11,8 @@ local defaults = {}
defaults.properties = Json.Object {}
local config = {}
config.properties = Settings.parse_object_safe (
"monitor.libcamera.properties", defaults.properties)
config.properties = Conf.get_section (
"monitor.libcamera.properties", defaults.properties): parse ()
function findDuplicate(parent, id, property, value)
for i = 0, id - 1, 1 do

View file

@ -11,8 +11,8 @@ local defaults = {}
defaults.properties = Json.Object {}
local config = {}
config.properties = Settings.parse_object_safe (
"monitor.v4l2.properties", defaults.properties)
config.properties = Conf.get_section (
"monitor.v4l2.properties", defaults.properties): parse ()
function findDuplicate(parent, id, property, value)
for i = 0, id - 1, 1 do

View file

@ -31,20 +31,15 @@ local cutils = require ("common-utils")
local defaults = {}
defaults.use_persistent_storage = true
defaults.use_headset_profile = true
defaults.app_settings = Json.Array {
"Firefox", "Chromium input", "Google Chrome input", "Brave input",
"Microsoft Edge input", "Vivaldi input", "ZOOM VoiceEngine",
"Telegram Desktop", "telegram-desktop", "linphone", "Mumble",
"WEBRTC VoiceEngine", "Skype"
}
defaults.app_settings = Json.Array {}
local config = {}
config.use_persistent_storage = Settings.parse_boolean_safe (
config.use_persistent_storage = Conf.get_value_boolean ("wireplumber.settings",
"policy.bluetooth.use-persistent-storage", defaults.use_persistent_storage)
config.use_headset_profile = Settings.parse_boolean_safe (
config.use_headset_profile = Conf.get_value_boolean ("wireplumber.settings",
"policy.bluetooth.media-role.use-headset-profile", defaults.use_headset_profile)
config.apps_setting = Settings.parse_array_safe (
"policy.bluetooth.media-role.applications", defaults.app_settings)
config.apps_setting = Conf.get_value ("wireplumber.settings",
"policy.bluetooth.media-role.applications", defaults.app_settings): parse ()
state = nil
headset_profiles = nil
@ -60,17 +55,17 @@ function handlePersistantSetting (enable)
end
end
local function settingsChangedCallback (_, setting, _)
if setting == "policy.bluetooth.use-persistent-storage" then
config.use_persistent_storage = Settings.parse_boolean_safe
("policy.bluetooth.use-persistent-storage", config.use_persistent_storage)
local function settingsChangedCallback (_, setting, json)
if setting == "policy.bluetooth.use-persistent-storage" and
json:is_boolean () then
config.use_persistent_storage = json:parse ()
handlePersistantSetting (config.use_persistent_storage)
elseif setting == "policy.bluetooth.media-role.use-headset-profile" then
config.use_headset_profile = Settings.parse_boolean_safe
("policy.bluetooth.media-role.use-headset-profile", config.use_headset_profile)
elseif setting == "policy.bluetooth.media-role.applications" then
local new_apps_setting = Settings.parse_array_safe
("policy.bluetooth.media-role.applications", Json.Array {})
elseif setting == "policy.bluetooth.media-role.use-headset-profile" and
json:is_boolean () then
config.use_headset_profile = json:parse ()
elseif setting == "policy.bluetooth.media-role.applications"
and json:is_array () then
local new_apps_setting = json:parse ()
if #new_apps_setting > 0 then
config.apps_setting = new_apps_setting
loadAppNames (config.apps_setting)

View file

@ -10,10 +10,10 @@ defaults.duck_level = 0.3
defaults.roles = Json.Object {}
local config = {}
config.duck_level = Settings.parse_float_safe (
config.duck_level = Conf.get_value_float ("wireplumber.settings",
"policy.default.duck-level", defaults.duck_level)
config.roles = Settings.parse_object_safe (
"endpoints-roles", defaults.roles)
config.roles = Conf.get_section (
"endpoint-roles", defaults.roles):parse ()
function findRole(role)
if role and not config.roles[role] then

View file

@ -11,8 +11,8 @@ local defaults = {}
defaults.roles = Json.Object {}
local config = {}
config.roles = Settings.parse_object_safe (
"endpoints-roles", defaults.roles)
config.roles = Conf.get_section (
"endpoint-roles", defaults.roles):parse ()
local self = {}
self.scanning = false

View file

@ -9,7 +9,7 @@ local defaults = {}
defaults.follow = true
local config = {}
config.follow = Settings.parse_boolean_safe (
config.follow = Conf.get_value_boolean ("wireplumber.settings",
"policy.default.follow", defaults.follow)
local self = {}

View file

@ -11,8 +11,8 @@ local defaults = {}
defaults.endpoints = Json.Object {}
local config = {}
config.endpoints = Settings.parse_object_safe (
"endpoints", defaults.endpoints)
config.endpoints = Conf.get_section (
"endpoints", defaults.endpoints):parse ()
function createEndpoint (factory_name, properties)
-- create endpoint

View file

@ -268,12 +268,6 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j2);
g_assert_true (wp_spa_json_parse_boolean (j2, &value));
g_assert_true (value);
value = wp_settings_parse_boolean_safe (s, "test-setting2", FALSE);
g_assert_true (value);
value = wp_settings_parse_boolean_safe (s, "test-setting-undefined", TRUE);
g_assert_true (value);
}
{
@ -284,12 +278,6 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j);
g_assert_true (wp_spa_json_parse_int (j, &value));
g_assert_cmpint (value, ==, -20);
value = wp_settings_parse_int_safe (s, "test-setting3-int", 3);
g_assert_cmpint (value, ==, -20);
value = wp_settings_parse_int_safe (s, "test-setting-undefined", 3);
g_assert_cmpint (value, ==, 3);
}
{
@ -303,20 +291,6 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_cmpstr (value, ==, "blahblah");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_parse_string_safe (s, "test-setting4-string",
"fallback-string");
g_assert_cmpstr (value, ==, "blahblah");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_parse_string_safe (s, "test-setting-undefined",
"fallback-string");
g_assert_cmpstr (value, ==, "fallback-string");
}
{
g_autofree gchar *value = NULL;
g_autoptr (WpSpaJson) j = NULL;
@ -340,12 +314,6 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j2);
g_assert_true (wp_spa_json_parse_float (j2, &value));
g_assert_cmpfloat_with_epsilon (value, 0.4, 0.001);
value = wp_settings_parse_float_safe (s, "test-setting-float1", 4.14);
g_assert_cmpfloat_with_epsilon (value, 3.14, 0.001);
value = wp_settings_parse_float_safe (s, "test-setting-undefined", 4.14);
g_assert_cmpfloat_with_epsilon (value, 4.14, 0.001);
}
/* test the wp_settings_get_instance () API */
@ -447,170 +415,6 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
}
}
static void
test_rules (TestSettingsFixture *self, gconstpointer data)
{
WpSettings *s = self->s;
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "juggler",
NULL);
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "jugglr",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string1", "copper",
"test-int1", "100",
NULL);
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string1", "copper",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "juggler",
NULL);
gint before = wp_properties_get_count (props), after = 0;
guint prop_int1 = 0;
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
after = wp_properties_get_count (props);
g_assert_cmpint (after-before, ==, 2);
g_assert_cmpstr (wp_properties_get(props, "prop-string1"), ==, "metal");
g_assert_cmpstr (wp_properties_get(props, "prop-string2"), ==, NULL);
g_assert_cmpstr (wp_properties_get(props, "prop-int1"), ==, "123");
spa_atou32 (wp_properties_get(props, "prop-int1"), &prop_int1, 0);
g_assert_cmpint (prop_int1, ==, 123);
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string4", "ferrous",
"test-int2", "100",
"test-string5", "blend",
NULL);
gint before = wp_properties_get_count (props), after = 0;
guint prop_int2 = 0;
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
after = wp_properties_get_count (props);
g_assert_cmpint (after-before, ==, 3);
g_assert_cmpstr (wp_properties_get(props, "prop-string1"), ==, NULL);
g_assert_cmpstr (wp_properties_get(props, "prop-string2"), ==, "standard");
g_assert_cmpstr (wp_properties_get(props, "prop-int2"), ==, "26");
spa_atou32 (wp_properties_get(props, "prop-int2"), &prop_int2, 0);
g_assert_cmpint (prop_int2, ==, 26);
g_assert_true (spa_atob(wp_properties_get(props, "prop-bool1")));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string6", "ethylene",
"test-int2", "625",
"test-string5", "blend",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
guint prop_int2 = 0;
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_true (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 2);
g_assert_cmpstr (wp_properties_get(applied_props, "prop-string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop-string2"),
==, "spray");
g_assert_cmpstr (wp_properties_get(applied_props, "prop-int2"), ==, "111");
spa_atou32 (wp_properties_get(applied_props, "prop-int2"), &prop_int2, 0);
g_assert_cmpint (prop_int2, ==, 111);
g_assert_false (spa_atob(wp_properties_get(applied_props, "prop-bool1")));
}
/* test the regular experession syntax */
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metal.iron",
"test.table.entry", "true",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_false (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_true (wp_settings_apply_rule (s, "rule_three", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 3);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.state"),
==, "solid");
g_assert_cmpstr (wp_properties_get(applied_props, "prop.example"),
==, "ferrous");
g_assert_true (spa_atob(wp_properties_get(applied_props,
"prop.electrical.conductivity")));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metal.iron",
"test.table.entry", "false",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_three", props,
NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metl.iron",
"test.table.entry", "true",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_three", props,
NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "gas.neon",
"test.table.entry", "maybe",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_false (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_true (wp_settings_apply_rule (s, "rule_three", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 3);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.state"),
==, "gas");
g_assert_cmpstr (wp_properties_get(applied_props, "prop.example"),
==, "neon");
g_assert_false (spa_atob(wp_properties_get(applied_props,
"prop.electrical.conductivity")));
}
}
void wp_settings_changed_callback (WpSettings *obj, const gchar *setting,
WpSpaJson *json, gpointer user_data)
{
@ -640,7 +444,6 @@ void wp_settings_changed_callback (WpSettings *obj, const gchar *setting,
}
}
static void
test_callbacks (TestSettingsFixture *self, gconstpointer data)
{
@ -722,8 +525,6 @@ main (gint argc, gchar *argv[])
test_metadata_setup, test_metadata, test_metadata_teardown);
g_test_add ("/wp/settings/wpsettings-creation-get", TestSettingsFixture, NULL,
test_wpsettings_setup, test_wpsettings, test_wpsettings_teardown);
g_test_add ("/wp/settings/wpsettings-creation-rules", TestSettingsFixture, NULL,
test_wpsettings_setup, test_rules, test_wpsettings_teardown);
g_test_add ("/wp/settings/wpsettings-callbacks", TestSettingsFixture, NULL,
test_wpsettings_setup, test_callbacks, test_wpsettings_teardown);

View file

@ -17,24 +17,12 @@ value = Settings.get ("test-setting2"):parse()
assert ("boolean" == type (value))
assert (value == true)
value = Settings.parse_boolean_safe ("test-setting2", false)
assert (value == true)
value = Settings.parse_boolean_safe ("test-setting-undefined", true)
assert (value == true)
-- test settings _get_int ()
value = Settings.get ("test-setting3-int"):parse()
assert ("number" == type (value))
assert (value == -20)
value = Settings.parse_int_safe ("test-setting3-int", 10)
assert (value == -20)
value = Settings.parse_int_safe ("test-setting-undefined", 10)
assert (value == 10)
-- test settings _get_string ()
value = Settings.get ("test-setting4-string"):parse()
@ -45,12 +33,6 @@ value = Settings.get ("test-setting5-string-with-quotes"):parse()
assert ("string" == type (value))
assert (value == "a string with \"quotes\"")
value = Settings.parse_string_safe ("test-setting4-string", "fallback-string")
assert (value == "blahblah")
value = Settings.parse_string_safe ("test-setting-undefined", "fallback-string")
assert (value == "fallback-string")
-- test settings _get_float ()
value = Settings.get ("test-setting-float1"):parse()
@ -60,34 +42,13 @@ assert ((value - 3.14) < 0.00001)
value = Settings.get ("test-setting-float2"):parse()
assert ((value - 0.4) < 0.00001)
value = Settings.parse_float_safe ("test-setting-float1", 4.14)
assert ((value - 3.14) < 0.00001)
value = Settings.parse_float_safe ("test-setting-undefined", 4.14)
assert ((value - 4.14) < 0.00001)
-- test settings _get ()
value = Settings.get ("test-setting-json")
assert (value ~= nil)
assert (value:is_array())
assert (value:get_data() == "[1, 2, 3]")
value = Settings.parse_array_safe ("test-setting-json", Json.Array {})
assert (value ~= nil)
assert (value[1] == 1)
assert (value[2] == 2)
assert (value[3] == 3)
value = Settings.parse_array_safe ("test-setting-undefined", nil)
assert (value ~= nil)
assert (#value == 0)
value = Settings.parse_array_safe ("test-setting-undefined", Json.Array { 1, 2 })
assert (value ~= nil)
assert (value[1] == 1)
assert (value[2] == 2)
value = Settings.get ("test-setting-json2")
value = Settings.get ("test-setting-json2", "test-settings")
assert (value ~= nil)
assert (value:is_array())
assert (value:get_data() ==
@ -111,132 +72,6 @@ assert (val.key1 == "value")
assert (val.key2 == 2)
assert (val.key3 == true)
value = Settings.parse_object_safe ("test-setting-json3", Json.Object {})
assert (value ~= nil)
assert (value.key1 == "value")
assert (value.key2 == 2)
assert (value.key3 == true)
value = Settings.parse_object_safe ("test-setting-undefined", nil)
assert (value ~= nil)
assert (#value == 0)
value = Settings.parse_object_safe ("test-setting-undefined", Json.Object { key1 = "value", key2 = 2})
assert (value ~= nil)
assert (value.key1 == "value")
assert (value.key2 == 2)
-- test rules
-- test #1
local cp = {
["test-string2"]="juggler"
}
local ap = {}
local applied, ap = Settings.apply_rule( "rule_one", cp)
assert (applied == true)
assert (ap["prop-string1"] == "metal")
assert (ap["prop-int1"] == "123")
assert (ap["blah blah"] == nil)
-- test #2
local cp = {
["test-string2"]="jugler"
}
local ap = {}
local applied, ap = Settings.apply_rule ("rule_one", cp)
assert (applied == false)
-- test #3
local cp = {
["test-string4"] = "ferrous",
["test-int2"] = "100",
["test-string5"] = "blend"
}
local applied, ap = Settings.apply_rule ("rule_one", cp)
assert (applied == true)
assert (ap["prop-string1"] == nil)
assert (ap["prop-string2"] == "standard")
assert (ap["prop-int2"] == "26")
assert (ap["prop-bool1"] == "true")
-- test #4
local cp = {
["test-string6"] = "alum",
}
local applied, ap = Settings.apply_rule ("rule_one", cp)
assert (applied == false)
-- test #5
local cp = {
["test-string6"] = "alum",
["test-int3"] = "24",
}
local applied, ap = Settings.apply_rule ("rule_one", cp)
assert (applied == true)
assert (ap["prop-string1"] == nil)
assert (ap["prop-string2"] == "standard")
assert (ap["prop-int2"] == "26")
assert (ap["prop-bool1"] == "true")
-- test #6
-- test regular expression syntax
local cp = {
["test.string6"] = "metal.ferrous",
["test.table.entry"] = "yes",
}
local applied, ap = Settings.apply_rule ("rule_three", cp)
assert (applied == false)
-- test #7
local cp = {
["test.string6"] = "metal.ferrous",
["test.table.entry"] = "true",
}
local applied, ap = Settings.apply_rule ("rule_three", cp)
assert (applied == true)
assert (ap["prop.electrical.conductivity"] == "true")
assert (ap["prop.state"] == "solid")
assert (ap["prop.example"] == "ferrous")
-- test #8
local cp = {
["test.string6"] = "gas.xenon",
["test.table.entry"] = "maybe",
}
local applied, ap = Settings.apply_rule ("rule_three", cp)
assert (applied == true)
assert (ap["prop.electrical.conductivity"] == "false")
assert (ap["prop.state"] == "gas")
assert (ap["prop.example"] == "neon")
-- test #9
local cp = {
["test-string6-wildcard"] = "wild_cat",
}
local applied, ap = Settings.apply_rule ("rule_three", cp)
assert (applied == true)
assert (ap["prop.electrical.conductivity"] == "true")
assert (ap["prop.state"] == "solid")
assert (ap["prop.example"] == "ferrous")
-- test callbacks
metadata_om = ObjectManager {