From 24c97b1c7e33dc1011eba60264c828587664c864 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 31 Jan 2022 17:59:18 +0100 Subject: [PATCH] context: add force-quantum and force-rate property Add a node.force-quantum and node.force-rate property. When no global quantum or rate is enforce with settings, the last updated node property is used as the quantum. Make jack use the force-quantum property when set_buffersize is used to make sure that the quantum is not just a suggestion but a hard forced one. This makes it possible for ardour or other jack apps to raise the quantum above the max-quantum but also ensure that it will not change by any other application (unless other jack apps). Fixes #2079 --- pipewire-jack/src/pipewire-jack.c | 1 + src/pipewire/context.c | 27 +++++++++++++++++++++++---- src/pipewire/impl-node.c | 24 ++++++++++++++++++++++-- src/pipewire/keys.h | 4 ++++ src/pipewire/private.h | 4 ++++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index 7193ce12b..3579c0fb0 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -3997,6 +3997,7 @@ int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) pw_thread_loop_lock(c->context.loop); pw_properties_set(c->props, PW_KEY_NODE_LATENCY, latency); + pw_properties_setf(c->props, PW_KEY_NODE_FORCE_QUANTUM, "%u", nframes); c->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS; c->info.props = &c->props->dict; diff --git a/src/pipewire/context.c b/src/pipewire/context.c index 7d4f602e9..5949c4ec9 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -1066,10 +1066,11 @@ static bool rates_contains(uint32_t *rates, uint32_t n_rates, uint32_t rate) 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; uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum; uint32_t *rates, n_rates, def_rate; - bool freewheel = false, force_rate; + bool freewheel = false, global_force_rate, force_rate, global_force_quantum; pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason); @@ -1082,7 +1083,10 @@ again: impl->recalc = true; get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum); - rates = get_rates(context, &def_rate, &n_rates, &force_rate); + rates = get_rates(context, &def_rate, &n_rates, &global_force_rate); + + global_force_quantum = rate_quantum == 0; + force_rate = global_force_rate; /* start from all drivers and group all nodes that are linked * to it. Some nodes are not (yet) linked to anything and they @@ -1164,6 +1168,7 @@ again: struct spa_fraction max_latency = SPA_FRACTION(0, 0); struct spa_fraction rate = SPA_FRACTION(0, 0); uint32_t quantum, target_rate, current_rate; + uint64_t quantum_stamp = 0, rate_stamp = 0; if (!n->driving || n->exported) continue; @@ -1175,6 +1180,20 @@ again: lock_quantum |= s->lock_quantum; lock_rate |= s->lock_rate; } + if (!global_force_quantum && s->force_quantum > 0 && + s->stamp > quantum_stamp) { + def_quantum = min_quantum = max_quantum = s->force_quantum; + rate_quantum = 0; + quantum_stamp = s->stamp; + } + if (!global_force_rate && s->force_rate > 0 && + s->stamp > rate_stamp) { + def_rate = s->force_rate; + force_rate = true; + n_rates = 1; + rates = &s->force_rate; + rate_stamp = s->stamp; + } /* smallest latencies */ if (latency.denom == 0 || @@ -1221,7 +1240,7 @@ again: target_rate); if (force_rate) { - if (context->settings.clock_rate_update_mode == CLOCK_RATE_UPDATE_MODE_HARD) + if (settings->clock_rate_update_mode == CLOCK_RATE_UPDATE_MODE_HARD) suspend_driver(context, n); } else { if (n->info.state >= PW_NODE_STATE_IDLE) @@ -1253,7 +1272,7 @@ again: quantum = SPA_CLAMP(quantum, min_quantum, max_quantum); quantum = SPA_MIN(quantum, lim_quantum); - if (context->settings.clock_power_of_two_quantum) + if (settings->clock_power_of_two_quantum) quantum = flp2(quantum); if (running && quantum != n->current_quantum && !lock_quantum) { diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 54d346465..cd8c8dcc8 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -857,6 +857,7 @@ static void check_properties(struct pw_impl_node *node) struct pw_context *context = node->context; const char *str, *recalc_reason = NULL; struct spa_fraction frac; + uint32_t value; bool driver; if ((str = pw_properties_get(node->properties, PW_KEY_PRIORITY_DRIVER))) { @@ -935,6 +936,15 @@ static void check_properties(struct pw_impl_node *node) } node->lock_quantum = pw_properties_get_bool(node->properties, PW_KEY_NODE_LOCK_QUANTUM, false); + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_FORCE_QUANTUM))) { + if (spa_atou32(str, &value, 0) && + node->force_quantum != value) { + node->force_quantum = value; + node->stamp = ++context->stamp; + recalc_reason = "force quantum changed"; + } + } + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_RATE))) { if (sscanf(str, "%u/%u", &frac.num, &frac.denom) == 2 && frac.denom != 0) { if (node->rate.num != frac.num || node->rate.denom != frac.denom) { @@ -948,6 +958,15 @@ static void check_properties(struct pw_impl_node *node) } node->lock_rate = pw_properties_get_bool(node->properties, PW_KEY_NODE_LOCK_RATE, false); + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_FORCE_RATE))) { + if (spa_atou32(str, &value, 0) && + node->force_rate != value) { + node->force_rate = value; + node->stamp = ++context->stamp; + recalc_reason = "force rate changed"; + } + } + pw_log_debug("%p: driver:%d recalc:%s active:%d", node, node->driver, recalc_reason, node->active); @@ -1787,6 +1806,7 @@ void pw_impl_node_destroy(struct pw_impl_node *node) struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); struct pw_impl_port *port; struct pw_impl_node *follower; + struct pw_context *context = node->context; bool active, had_driver; active = node->active; @@ -1836,7 +1856,7 @@ void pw_impl_node_destroy(struct pw_impl_node *node) } if (active || had_driver) - pw_context_recalc_graph(node->context, + pw_context_recalc_graph(context, "active node destroy"); pw_log_debug("%p: free", node); @@ -1858,7 +1878,7 @@ void pw_impl_node_destroy(struct pw_impl_node *node) clear_info(node); - spa_system_close(node->context->data_system, node->source.fd); + spa_system_close(context->data_system, node->source.fd); free(impl); } diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index a71797ae7..55c37b0f1 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -161,10 +161,14 @@ extern "C" { * node as a fraction. Ex: 1024/48000 */ #define PW_KEY_NODE_LOCK_QUANTUM "node.lock-quantum" /**< don't change quantum when this node * is active */ +#define PW_KEY_NODE_FORCE_QUANTUM "node.force-quantum" /**< force a quantum while the node is + * active */ #define PW_KEY_NODE_RATE "node.rate" /**< the requested rate of the graph as * a fraction. Ex: 1/48000 */ #define PW_KEY_NODE_LOCK_RATE "node.lock-rate" /**< don't change rate when this node * is active */ +#define PW_KEY_NODE_FORCE_RATE "node.force-rate" /**< force a rate while the node is + * active */ #define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */ #define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */ diff --git a/src/pipewire/private.h b/src/pipewire/private.h index fd5e70d4c..64dd5bf83 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -424,6 +424,7 @@ struct pw_context { struct pw_mempool *pool; /**< global memory pool */ + uint64_t stamp; uint64_t serial; struct pw_map globals; /**< map of globals */ @@ -713,6 +714,9 @@ struct pw_impl_node { struct spa_fraction latency; /**< requested latency */ struct spa_fraction max_latency; /**< maximum latency */ struct spa_fraction rate; /**< requested rate */ + uint32_t force_quantum; /**< forced quantum */ + uint32_t force_rate; /**< forced rate */ + uint32_t stamp; /**< stamp of last update */ struct spa_source source; /**< source to remotely trigger this node */ struct pw_memblock *activation; struct {