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
This commit is contained in:
Wim Taymans 2022-01-31 17:59:18 +01:00
parent 54d50b943f
commit 24c97b1c7e
5 changed files with 54 additions and 6 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 {