diff --git a/src/pipewire/context.c b/src/pipewire/context.c index a48e225fc..422e8cf83 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -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); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 388ca6bc8..ab131508c 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -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 */ diff --git a/src/pipewire/settings.c b/src/pipewire/settings.c index 950e9df69..b0c0b3381 100644 --- a/src/pipewire/settings.c +++ b/src/pipewire/settings.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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,