impl-node: rework quantum and max_quantum handling

Rework the quantum and max_quantum handling. Work directly with the
latency fractions and calculate the final quantum size until we know
the samplerate.
This commit is contained in:
Wim Taymans 2021-07-30 11:38:53 +02:00
parent 7bec96640c
commit 6acf72dc30
3 changed files with 53 additions and 45 deletions

View file

@ -1019,6 +1019,22 @@ static void suspend_driver(struct pw_context *context, struct pw_impl_node *n)
pw_impl_node_set_state(n, PW_NODE_STATE_SUSPENDED); pw_impl_node_set_state(n, PW_NODE_STATE_SUSPENDED);
} }
/* find smaller power of 2 */
static uint32_t flp2(uint32_t x)
{
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
}
static int64_t fraction_compare(const struct spa_fraction *a, const struct spa_fraction *b)
{
return (int64_t)(a->num * b->denom) - (int64_t)(b->num * a->denom);
}
int pw_context_recalc_graph(struct pw_context *context, const char *reason) int pw_context_recalc_graph(struct pw_context *context, const char *reason)
{ {
struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this); struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
@ -1113,7 +1129,9 @@ again:
/* assign final quantum and set state for followers and drivers */ /* assign final quantum and set state for followers and drivers */
spa_list_for_each(n, &context->driver_list, driver_link) { spa_list_for_each(n, &context->driver_list, driver_link) {
bool running = false, lock_quantum = false; bool running = false, lock_quantum = false;
uint32_t quantum = 0; struct spa_fraction latency = SPA_FRACTION(0, 0);
struct spa_fraction max_latency = SPA_FRACTION(0, 0);
uint32_t quantum;
if (!n->driving || n->exported) if (!n->driving || n->exported)
continue; continue;
@ -1123,22 +1141,33 @@ again:
lock_quantum |= s->lock_quantum; lock_quantum |= s->lock_quantum;
if (s->quantum_size > 0) { if (latency.denom == 0 ||
if (quantum == 0 || s->quantum_size < quantum) (s->latency.denom > 0 &&
quantum = s->quantum_size; fraction_compare(&s->latency, &latency) < 0))
} latency = s->latency;
if (s->max_quantum_size > 0) {
if (s->max_quantum_size < max_quantum) if (max_latency.denom == 0 ||
max_quantum = s->max_quantum_size; (s->max_latency.denom > 0 &&
} fraction_compare(&s->max_latency, &max_latency) < 0))
max_latency = s->max_latency;
if (s->active) if (s->active)
running = !n->passive; running = !n->passive;
} }
if (quantum == 0) if (max_latency.denom != 0) {
quantum = def_quantum; uint32_t tmp = (max_latency.num * def_rate / max_latency.denom);
if (tmp < max_quantum)
max_quantum = tmp;
}
quantum = def_quantum;
if (latency.denom != 0)
quantum = (latency.num * def_rate / latency.denom);
quantum = SPA_CLAMP(quantum, min_quantum, max_quantum); quantum = SPA_CLAMP(quantum, min_quantum, max_quantum);
if (context->settings.clock_power_of_two_quantum)
quantum = flp2(quantum);
if (def_rate != n->rt.position->clock.rate.denom) { if (def_rate != n->rt.position->clock.rate.denom) {
pw_log_info("(%s-%u) new rate:%u->%u", pw_log_info("(%s-%u) new rate:%u->%u",
n->name, n->info.id, n->name, n->info.id,

View file

@ -817,6 +817,7 @@ static void check_properties(struct pw_impl_node *node)
struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
struct pw_context *context = node->context; struct pw_context *context = node->context;
const char *str, *recalc_reason = NULL; const char *str, *recalc_reason = NULL;
struct spa_fraction frac;
bool driver; bool driver;
if ((str = pw_properties_get(node->properties, PW_KEY_PRIORITY_DRIVER))) { if ((str = pw_properties_get(node->properties, PW_KEY_PRIORITY_DRIVER))) {
@ -873,43 +874,23 @@ static void check_properties(struct pw_impl_node *node)
node->want_driver = true; node->want_driver = true;
if ((str = pw_properties_get(node->properties, PW_KEY_NODE_LATENCY))) { if ((str = pw_properties_get(node->properties, PW_KEY_NODE_LATENCY))) {
uint32_t num, denom; if (sscanf(str, "%u/%u", &frac.num, &frac.denom) == 2 && frac.denom != 0) {
if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) { if (node->latency.num != frac.num || node->latency.denom != frac.denom) {
uint32_t quantum_size; pw_log_info("(%s-%u) latency:%u/%u -> %u/%u", node->name,
node->info.id, node->latency.num,
node->latency = SPA_FRACTION(num, denom); node->latency.denom, frac.num, frac.denom);
quantum_size = (num * context->settings.clock_rate / denom); node->latency = frac;
if (context->settings.clock_power_of_two_quantum)
quantum_size = flp2(quantum_size);
if (quantum_size != node->quantum_size) {
pw_log_debug(NAME" %p: latency '%s' quantum %u/%u",
node, str, quantum_size, context->settings.clock_rate);
pw_log_info("(%s-%u) latency:%s ->quantum %u/%u", node->name,
node->info.id, str, quantum_size,
context->settings.clock_rate);
node->quantum_size = quantum_size;
recalc_reason = "quantum changed"; recalc_reason = "quantum changed";
} }
} }
} }
if ((str = pw_properties_get(node->properties, PW_KEY_NODE_MAX_LATENCY))) { if ((str = pw_properties_get(node->properties, PW_KEY_NODE_MAX_LATENCY))) {
uint32_t num, denom; if (sscanf(str, "%u/%u", &frac.num, &frac.denom) == 2 && frac.denom != 0) {
if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) { if (node->max_latency.num != frac.num || node->max_latency.denom != frac.denom) {
uint32_t max_quantum_size; pw_log_info("(%s-%u) max-latency:%u/%u -> %u/%u", node->name,
node->info.id, node->max_latency.num,
node->max_latency = SPA_FRACTION(num, denom); node->max_latency.denom, frac.num, frac.denom);
max_quantum_size = (num * context->settings.clock_rate / denom); node->max_latency = frac;
if (context->settings.clock_power_of_two_quantum)
max_quantum_size = flp2(max_quantum_size);
if (max_quantum_size != node->max_quantum_size) {
pw_log_debug(NAME" %p: max latency '%s' quantum %u/%u",
node, str, max_quantum_size, context->settings.clock_rate);
pw_log_info("(%s-%u) max latency:%s ->quantum %u/%u", node->name,
node->info.id, str, max_quantum_size,
context->settings.clock_rate);
node->max_quantum_size = max_quantum_size;
recalc_reason = "max quantum changed"; recalc_reason = "max quantum changed";
} }
} }

View file

@ -701,9 +701,7 @@ struct pw_impl_node {
struct pw_loop *data_loop; /**< the data loop for this node */ struct pw_loop *data_loop; /**< the data loop for this node */
struct spa_fraction latency; /**< requested latency */ struct spa_fraction latency; /**< requested latency */
uint32_t quantum_size; /**< desired quantum */
struct spa_fraction max_latency; /**< maximum latency */ struct spa_fraction max_latency; /**< maximum latency */
uint32_t max_quantum_size; /**< max supported quantum */
struct spa_source source; /**< source to remotely trigger this node */ struct spa_source source; /**< source to remotely trigger this node */
struct pw_memblock *activation; struct pw_memblock *activation;
struct { struct {