context: keep per node quantum and rate settings

Copy the global quantum and rate limits before applying node specific
settings. Otherwise one node settings will propagate to the defaults
of the next nodes, which can result in impossible or wrong settings.

See #2925
This commit is contained in:
Wim Taymans 2023-01-09 17:54:23 +01:00
parent 395749fea9
commit 9f3237b74e

View file

@ -917,7 +917,7 @@ static inline void get_quantums(struct pw_context *context, uint32_t *def,
*limit = s->clock_quantum_limit;
}
static inline uint32_t *get_rates(struct pw_context *context, uint32_t *def, uint32_t *n_rates,
static inline const uint32_t *get_rates(struct pw_context *context, uint32_t *def, uint32_t *n_rates,
bool *force)
{
struct settings *s = &context->settings;
@ -971,7 +971,7 @@ static int fraction_compare(const struct spa_fraction *a, const struct spa_fract
return fa < fb ? -1 : (fa > fb ? 1 : 0);
}
static uint32_t find_best_rate(uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t best)
static uint32_t find_best_rate(const uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t best)
{
uint32_t i;
for (i = 0; i < n_rates; i++) {
@ -1005,9 +1005,10 @@ int pw_context_recalc_graph(struct pw_context *context, const char *reason)
struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
struct settings *settings = &context->settings;
struct pw_impl_node *n, *s, *target, *fallback;
const uint32_t *rates;
uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
uint32_t *rates, n_rates, def_rate;
bool freewheel = false, global_force_rate, force_rate, force_quantum, global_force_quantum;
uint32_t n_rates, def_rate;
bool freewheel = false, global_force_rate, global_force_quantum;
struct spa_list collect;
pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
@ -1023,8 +1024,7 @@ again:
get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum);
rates = get_rates(context, &def_rate, &n_rates, &global_force_rate);
force_quantum = global_force_quantum = rate_quantum == 0;
force_rate = global_force_rate;
global_force_quantum = rate_quantum == 0;
/* start from all drivers and group all nodes that are linked
* to it. Some nodes are not (yet) linked to anything and they
@ -1121,10 +1121,25 @@ again:
struct spa_fraction rate = SPA_FRACTION(0, 0);
uint32_t quantum, target_rate, current_rate;
uint64_t quantum_stamp = 0, rate_stamp = 0;
bool force_rate, force_quantum;
const uint32_t *node_rates;
uint32_t node_n_rates, node_def_rate;
uint32_t node_max_quantum, node_min_quantum, node_def_quantum, node_rate_quantum;
if (!n->driving || n->exported)
continue;
node_def_quantum = def_quantum;
node_min_quantum = min_quantum;
node_max_quantum = max_quantum;
node_rate_quantum = rate_quantum;
force_quantum = global_force_quantum;
node_def_rate = def_rate;
node_n_rates = n_rates;
node_rates = rates;
force_rate = global_force_rate;
/* collect quantum and rate */
spa_list_for_each(s, &n->follower_list, follower_link) {
@ -1138,17 +1153,17 @@ again:
}
if (!global_force_quantum && s->force_quantum > 0 &&
s->stamp > quantum_stamp) {
def_quantum = min_quantum = max_quantum = s->force_quantum;
rate_quantum = 0;
node_def_quantum = node_min_quantum = node_max_quantum = s->force_quantum;
node_rate_quantum = 0;
quantum_stamp = s->stamp;
force_quantum = true;
}
if (!global_force_rate && s->force_rate > 0 &&
s->stamp > rate_stamp) {
def_rate = s->force_rate;
node_def_rate = s->force_rate;
node_n_rates = 1;
node_rates = &s->force_rate;
force_rate = true;
n_rates = 1;
rates = &s->force_rate;
rate_stamp = s->stamp;
}
@ -1198,9 +1213,9 @@ again:
/* Here we are allowed to change the rate of the driver.
* Start with the default rate. If the desired rate is
* allowed, switch to it */
target_rate = def_rate;
target_rate = node_def_rate;
if (rate.denom != 0 && rate.num == 1)
target_rate = find_best_rate(rates, n_rates,
target_rate = find_best_rate(node_rates, node_n_rates,
rate.denom, target_rate);
}
@ -1233,24 +1248,24 @@ again:
goto again;
}
if (rate_quantum != 0 && current_rate != rate_quantum) {
if (node_rate_quantum != 0 && current_rate != node_rate_quantum) {
/* the quantum values are scaled with the current rate */
def_quantum = def_quantum * current_rate / rate_quantum;
min_quantum = min_quantum * current_rate / rate_quantum;
max_quantum = max_quantum * current_rate / rate_quantum;
node_def_quantum = node_def_quantum * current_rate / node_rate_quantum;
node_min_quantum = node_min_quantum * current_rate / node_rate_quantum;
node_max_quantum = node_max_quantum * current_rate / node_rate_quantum;
}
/* calculate desired quantum */
if (max_latency.denom != 0) {
uint32_t tmp = (max_latency.num * current_rate / max_latency.denom);
if (tmp < max_quantum)
max_quantum = tmp;
if (tmp < node_max_quantum)
node_max_quantum = tmp;
}
quantum = def_quantum;
quantum = node_def_quantum;
if (latency.denom != 0)
quantum = (latency.num * current_rate / latency.denom);
quantum = SPA_CLAMP(quantum, min_quantum, max_quantum);
quantum = SPA_CLAMP(quantum, node_min_quantum, node_max_quantum);
quantum = SPA_MIN(quantum, lim_quantum);
if (settings->clock_power_of_two_quantum)