settings: Add more runtime settings

Move settings defaults initialization to the settings file.
Expose clock.rate, clock.allowed-rates and clock.quantum as runtime
settings.
This commit is contained in:
Wim Taymans 2021-11-26 16:47:43 +01:00
parent 5cff20eba4
commit 1b06d4d7c4
3 changed files with 175 additions and 121 deletions

View file

@ -40,7 +40,6 @@
#include <spa/utils/string.h>
#include <spa/debug/format.h>
#include <spa/debug/types.h>
#include <spa/utils/json.h>
#include <pipewire/impl.h>
#include <pipewire/private.h>
@ -52,19 +51,6 @@
PW_LOG_TOPIC_EXTERN(log_context);
#define PW_LOG_TOPIC_DEFAULT log_context
#define DEFAULT_CLOCK_RATE 48000u
#define DEFAULT_CLOCK_QUANTUM 1024u
#define DEFAULT_CLOCK_MIN_QUANTUM 32u
#define DEFAULT_CLOCK_MAX_QUANTUM 8192u
#define DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM true
#define DEFAULT_VIDEO_WIDTH 640
#define DEFAULT_VIDEO_HEIGHT 480
#define DEFAULT_VIDEO_RATE_NUM 25u
#define DEFAULT_VIDEO_RATE_DENOM 1u
#define DEFAULT_LINK_MAX_BUFFERS 64u
#define DEFAULT_MEM_WARN_MLOCK false
#define DEFAULT_MEM_ALLOW_MLOCK true
/** \cond */
struct impl {
struct pw_context this;
@ -115,101 +101,6 @@ static void fill_properties(struct pw_context *context)
pw_properties_set(properties, PW_KEY_CORE_NAME, context->core->info.name);
}
static uint32_t get_default_int(struct pw_properties *properties, const char *name, uint32_t def)
{
uint32_t val;
const char *str;
if ((str = pw_properties_get(properties, name)) != NULL)
val = atoi(str);
else {
val = def;
pw_properties_setf(properties, name, "%d", val);
}
return val;
}
static bool get_default_bool(struct pw_properties *properties, const char *name, bool def)
{
bool val;
const char *str;
if ((str = pw_properties_get(properties, name)) != NULL)
val = pw_properties_parse_bool(str);
else {
val = def;
pw_properties_set(properties, name, val ? "true" : "false");
}
return val;
}
static bool rates_contains(uint32_t *rates, uint32_t n_rates, uint32_t rate)
{
uint32_t i;
for (i = 0; i < n_rates; i++)
if (rates[i] == rate)
return true;
return false;
}
static uint32_t parse_clock_rate(struct pw_properties *properties, const char *name,
uint32_t *rates, uint32_t def)
{
const char *str;
uint32_t count = 0, r;
struct spa_json it[2];
char v[256];
if ((str = pw_properties_get(properties, name)) == NULL)
goto fallback;
spa_json_init(&it[0], str, strlen(str));
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], str, strlen(str));
while (spa_json_get_string(&it[1], v, sizeof(v)-1) > 0 &&
count < MAX_RATES) {
if (spa_atou32(v, &r, 0))
rates[count++] = r;
}
if (count == 0 ||!rates_contains(rates, count, def))
goto fallback;
return count;
fallback:
rates[0] = def;
pw_properties_setf(properties, name, "[ %u ]", def);
return 1;
}
static void fill_defaults(struct pw_context *this)
{
struct pw_properties *p = this->properties;
struct settings *d = &this->defaults;
d->clock_rate = get_default_int(p, "default.clock.rate", DEFAULT_CLOCK_RATE);
d->n_clock_rates = parse_clock_rate(p, "default.clock.allowed-rates", d->clock_rates, d->clock_rate);
d->clock_quantum = get_default_int(p, "default.clock.quantum", DEFAULT_CLOCK_QUANTUM);
d->clock_min_quantum = get_default_int(p, "default.clock.min-quantum", DEFAULT_CLOCK_MIN_QUANTUM);
d->clock_max_quantum = get_default_int(p, "default.clock.max-quantum", DEFAULT_CLOCK_MAX_QUANTUM);
d->video_size.width = get_default_int(p, "default.video.width", DEFAULT_VIDEO_WIDTH);
d->video_size.height = get_default_int(p, "default.video.height", DEFAULT_VIDEO_HEIGHT);
d->video_rate.num = get_default_int(p, "default.video.rate.num", DEFAULT_VIDEO_RATE_NUM);
d->video_rate.denom = get_default_int(p, "default.video.rate.denom", DEFAULT_VIDEO_RATE_DENOM);
d->log_level = get_default_int(p, "log.level", pw_log_level);
d->clock_power_of_two_quantum = get_default_bool(p, "clock.power-of-two-quantum",
DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM);
d->link_max_buffers = get_default_int(p, "link.max-buffers", DEFAULT_LINK_MAX_BUFFERS);
d->mem_warn_mlock = get_default_bool(p, "mem.warn-mlock", DEFAULT_MEM_WARN_MLOCK);
d->mem_allow_mlock = get_default_bool(p, "mem.allow-mlock", DEFAULT_MEM_ALLOW_MLOCK);
d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum,
CLOCK_MIN_QUANTUM, CLOCK_MAX_QUANTUM);
d->clock_min_quantum = SPA_CLAMP(d->clock_min_quantum,
CLOCK_MIN_QUANTUM, d->clock_max_quantum);
d->clock_quantum = SPA_CLAMP(d->clock_quantum,
d->clock_min_quantum, d->clock_max_quantum);
}
static int try_load_conf(struct pw_context *this, const char *conf_prefix,
const char *conf_name, struct pw_properties *conf)
{
@ -291,6 +182,7 @@ static void init_plugin_loader(struct impl *impl)
*
* \param main_loop the main loop to use
* \param properties extra properties for the context, ownership it taken
*
* \return a newly allocated context object
*/
SPA_EXPORT
@ -415,7 +307,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
pw_log_info("%p: mlockall succeeded", impl);
}
fill_defaults(this);
pw_settings_init(this);
this->settings = this->defaults;
pr = pw_properties_copy(properties);
@ -500,7 +392,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
context_set_freewheel(this, false);
pw_settings_init(this);
pw_settings_expose(this);
pw_log_debug("%p: created", this);
@ -1148,6 +1040,15 @@ static int fraction_compare(const struct spa_fraction *a, const struct spa_fract
return fa < fb ? -1 : (fa > fb ? 1 : 0);
}
static bool rates_contains(uint32_t *rates, uint32_t n_rates, uint32_t rate)
{
uint32_t i;
for (i = 0; i < n_rates; i++)
if (rates[i] == rate)
return true;
return false;
}
int pw_context_recalc_graph(struct pw_context *context, const char *reason)
{
struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);

View file

@ -1261,7 +1261,8 @@ bool pw_log_is_default(void);
void pw_log_init(void);
void pw_log_deinit(void);
int pw_settings_init(struct pw_context *context);
void pw_settings_init(struct pw_context *context);
int pw_settings_expose(struct pw_context *context);
void pw_settings_clean(struct pw_context *context);
/** \endcond */

View file

@ -29,6 +29,7 @@
#include <spa/monitor/device.h>
#include <spa/monitor/utils.h>
#include <spa/pod/filter.h>
#include <spa/utils/json.h>
#include <pipewire/impl.h>
#include <pipewire/private.h>
@ -39,6 +40,19 @@
#define NAME "settings"
#define DEFAULT_CLOCK_RATE 48000u
#define DEFAULT_CLOCK_QUANTUM 1024u
#define DEFAULT_CLOCK_MIN_QUANTUM 32u
#define DEFAULT_CLOCK_MAX_QUANTUM 8192u
#define DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM true
#define DEFAULT_VIDEO_WIDTH 640
#define DEFAULT_VIDEO_HEIGHT 480
#define DEFAULT_VIDEO_RATE_NUM 25u
#define DEFAULT_VIDEO_RATE_DENOM 1u
#define DEFAULT_LINK_MAX_BUFFERS 64u
#define DEFAULT_MEM_WARN_MLOCK false
#define DEFAULT_MEM_ALLOW_MLOCK true
struct impl {
struct pw_context *context;
struct pw_impl_metadata *metadata;
@ -53,6 +67,81 @@ static void metadata_destroy(void *data)
impl->metadata = NULL;
}
static uint32_t get_default_int(struct pw_properties *properties, const char *name, uint32_t def)
{
uint32_t val;
const char *str;
if ((str = pw_properties_get(properties, name)) != NULL)
val = atoi(str);
else {
val = def;
pw_properties_setf(properties, name, "%d", val);
}
return val;
}
static bool get_default_bool(struct pw_properties *properties, const char *name, bool def)
{
bool val;
const char *str;
if ((str = pw_properties_get(properties, name)) != NULL)
val = pw_properties_parse_bool(str);
else {
val = def;
pw_properties_set(properties, name, val ? "true" : "false");
}
return val;
}
static bool uint32_array_contains(uint32_t *vals, uint32_t n_vals, uint32_t val)
{
uint32_t i;
for (i = 0; i < n_vals; i++)
if (vals[i] == val)
return true;
return false;
}
static uint32_t parse_uint32_array(const char *str, uint32_t *vals, uint32_t max, uint32_t def)
{
uint32_t count = 0, r;
struct spa_json it[2];
char v[256];
spa_json_init(&it[0], str, strlen(str));
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], str, strlen(str));
while (spa_json_get_string(&it[1], v, sizeof(v)-1) > 0 &&
count < max) {
if (spa_atou32(v, &r, 0))
vals[count++] = r;
}
if (!uint32_array_contains(vals, count, def))
count = 0;
return count;
}
static uint32_t parse_clock_rate(struct pw_properties *properties, const char *name,
uint32_t *rates, uint32_t def)
{
const char *str;
uint32_t count = 0;
if ((str = pw_properties_get(properties, name)) == NULL)
return 0;
count = parse_uint32_array(str, rates, MAX_RATES, def);
if (count == 0)
goto fallback;
return count;
fallback:
rates[0] = def;
pw_properties_setf(properties, name, "[ %u ]", def);
return 1;
}
static int metadata_property(void *data, uint32_t subject, const char *key,
const char *type, const char *value)
{
@ -69,6 +158,22 @@ static int metadata_property(void *data, uint32_t subject, const char *key,
if (spa_streq(key, "log.level")) {
v = value ? atoi(value) : 3;
pw_log_set_level(v);
} else if (spa_streq(key, "clock.rate")) {
v = value ? atoi(value) : 0;
s->clock_rate = v == 0 ? d->clock_rate : v;
recalc = true;
} else if (spa_streq(key, "clock.allowed-rates")) {
s->n_clock_rates = parse_uint32_array(value,
s->clock_rates, MAX_RATES, s->clock_rate);
if (s->n_clock_rates == 0) {
s->n_clock_rates = d->n_clock_rates;
memcpy(s->clock_rates, d->clock_rates, MAX_RATES * sizeof(uint32_t));
}
recalc = true;
} else if (spa_streq(key, "clock.quantum")) {
v = value ? atoi(value) : 0;
s->clock_quantum = v == 0 ? d->clock_quantum : v;
recalc = true;
} else if (spa_streq(key, "clock.min-quantum")) {
v = value ? atoi(value) : 0;
s->clock_min_quantum = v == 0 ? d->clock_min_quantum : v;
@ -98,23 +203,70 @@ static const struct pw_impl_metadata_events metadata_events = {
.property = metadata_property,
};
static void init_defaults(struct impl *impl)
void pw_settings_init(struct pw_context *this)
{
struct settings *s = &impl->context->settings;
struct pw_properties *p = this->properties;
struct settings *d = &this->defaults;
pw_impl_metadata_set_propertyf(impl->metadata,
d->clock_rate = get_default_int(p, "default.clock.rate", DEFAULT_CLOCK_RATE);
d->n_clock_rates = parse_clock_rate(p, "default.clock.allowed-rates", d->clock_rates, d->clock_rate);
d->clock_quantum = get_default_int(p, "default.clock.quantum", DEFAULT_CLOCK_QUANTUM);
d->clock_min_quantum = get_default_int(p, "default.clock.min-quantum", DEFAULT_CLOCK_MIN_QUANTUM);
d->clock_max_quantum = get_default_int(p, "default.clock.max-quantum", DEFAULT_CLOCK_MAX_QUANTUM);
d->video_size.width = get_default_int(p, "default.video.width", DEFAULT_VIDEO_WIDTH);
d->video_size.height = get_default_int(p, "default.video.height", DEFAULT_VIDEO_HEIGHT);
d->video_rate.num = get_default_int(p, "default.video.rate.num", DEFAULT_VIDEO_RATE_NUM);
d->video_rate.denom = get_default_int(p, "default.video.rate.denom", DEFAULT_VIDEO_RATE_DENOM);
d->log_level = get_default_int(p, "log.level", pw_log_level);
d->clock_power_of_two_quantum = get_default_bool(p, "clock.power-of-two-quantum",
DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM);
d->link_max_buffers = get_default_int(p, "link.max-buffers", DEFAULT_LINK_MAX_BUFFERS);
d->mem_warn_mlock = get_default_bool(p, "mem.warn-mlock", DEFAULT_MEM_WARN_MLOCK);
d->mem_allow_mlock = get_default_bool(p, "mem.allow-mlock", DEFAULT_MEM_ALLOW_MLOCK);
d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum,
CLOCK_MIN_QUANTUM, CLOCK_MAX_QUANTUM);
d->clock_min_quantum = SPA_CLAMP(d->clock_min_quantum,
CLOCK_MIN_QUANTUM, d->clock_max_quantum);
d->clock_quantum = SPA_CLAMP(d->clock_quantum,
d->clock_min_quantum, d->clock_max_quantum);
}
static void expose_settings(struct pw_context *context, struct pw_impl_metadata *metadata)
{
struct settings *s = &context->settings;
uint32_t i, o;
char rates[MAX_RATES*16] = "";
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "log.level", "", "%d", s->log_level);
pw_impl_metadata_set_propertyf(impl->metadata,
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.rate", "", "%d", s->clock_rate);
for (i = 0, o = 0; i < s->n_clock_rates; i++) {
int r = snprintf(rates+o, sizeof(rates)-o, "%s%d", i == 0 ? "" : ", ",
s->clock_rates[i]);
if (r < 0 || o + r >= (int)sizeof(rates)) {
snprintf(rates, sizeof(rates), "%d", s->clock_rate);
break;
}
o += r;
}
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.allowed-rates", "", "[ %s ]", rates);
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.quantum", "", "%d", s->clock_quantum);
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.min-quantum", "", "%d", s->clock_min_quantum);
pw_impl_metadata_set_propertyf(impl->metadata,
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.max-quantum", "", "%d", s->clock_max_quantum);
pw_impl_metadata_set_propertyf(impl->metadata,
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.force-quantum", "", "%d", s->clock_force_quantum);
pw_impl_metadata_set_propertyf(impl->metadata,
pw_impl_metadata_set_propertyf(metadata,
PW_ID_CORE, "clock.force-rate", "", "%d", s->clock_force_rate);
}
int pw_settings_init(struct pw_context *context)
int pw_settings_expose(struct pw_context *context)
{
struct impl *impl;
@ -127,7 +279,7 @@ int pw_settings_init(struct pw_context *context)
if (impl->metadata == NULL)
goto error_free;
init_defaults(impl);
expose_settings(context, impl->metadata);
pw_impl_metadata_add_listener(impl->metadata,
&impl->metadata_listener,