diff --git a/spa/include/spa/node/keys.h b/spa/include/spa/node/keys.h index 3e0f1f38b..926cbdef5 100644 --- a/spa/include/spa/node/keys.h +++ b/spa/include/spa/node/keys.h @@ -32,6 +32,7 @@ extern "C" { /** node keys */ #define SPA_KEY_NODE_NAME "node.name" /**< a node name */ #define SPA_KEY_NODE_LATENCY "node.latency" /**< the requested node latency */ +#define SPA_KEY_NODE_MAX_LATENCY "node.max-latency" /**< maximum supported latency */ #define SPA_KEY_NODE_DRIVER "node.driver" /**< the node can be a driver */ #define SPA_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< call the process function even if diff --git a/spa/plugins/alsa/alsa-pcm-sink.c b/spa/plugins/alsa/alsa-pcm-sink.c index fe7284295..06210911e 100644 --- a/spa/plugins/alsa/alsa-pcm-sink.c +++ b/spa/plugins/alsa/alsa-pcm-sink.c @@ -284,7 +284,7 @@ static void emit_node_info(struct state *this, bool full) items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); if (this->have_format) { snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate); - items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); } this->info.props = &SPA_DICT_INIT(items, n_items); diff --git a/spa/plugins/alsa/alsa-pcm-source.c b/spa/plugins/alsa/alsa-pcm-source.c index a14ee8ec8..393f450e6 100644 --- a/spa/plugins/alsa/alsa-pcm-source.c +++ b/spa/plugins/alsa/alsa-pcm-source.c @@ -285,7 +285,7 @@ static void emit_node_info(struct state *this, bool full) items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); if (this->have_format) { snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate); - items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); } this->info.props = &SPA_DICT_INIT(items, n_items); diff --git a/src/pipewire/context.c b/src/pipewire/context.c index 459a0eb32..cd7898c97 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -991,32 +991,34 @@ int pw_context_recalc_graph(struct pw_context *context, const char *reason) /* assign final quantum and set state for followers and drivers */ spa_list_for_each(n, &context->driver_list, driver_link) { bool running = false; - uint32_t max_quantum = 0; - uint32_t min_quantum = 0; - uint32_t quantum; + uint32_t max_quantum = context->defaults.clock_max_quantum; + uint32_t quantum = 0; if (!n->driving || n->exported) continue; /* collect quantum and count active nodes */ spa_list_for_each(s, &n->follower_list, follower_link) { + if (s->quantum_size > 0) { - if (min_quantum == 0 || s->quantum_size < min_quantum) - min_quantum = s->quantum_size; - if (s->quantum_size > max_quantum) - max_quantum = s->quantum_size; + if (quantum == 0 || s->quantum_size < quantum) + quantum = s->quantum_size; + } + if (s->max_quantum_size > 0) { + if (s->max_quantum_size < max_quantum) + max_quantum = s->max_quantum_size; } if (s == n) continue; if (s->active) running = !n->passive; } - quantum = min_quantum; if (quantum == 0) quantum = context->defaults.clock_quantum; + quantum = SPA_CLAMP(quantum, context->defaults.clock_min_quantum, - context->defaults.clock_max_quantum); + max_quantum); if (n->rt.position && quantum != n->rt.position->clock.duration) { pw_log_info("(%s-%u) new quantum:%"PRIu64"->%u", diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 152f46908..0ff8a034a 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -865,6 +865,26 @@ static void check_properties(struct pw_impl_node *node) } } } + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_MAX_LATENCY))) { + uint32_t num, denom; + if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) { + uint32_t max_quantum_size; + + node->max_latency = SPA_FRACTION(num, denom); + max_quantum_size = flp2((num * context->defaults.clock_rate / denom)); + + 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->defaults.clock_rate); + pw_log_info("(%s-%u) max latency:%s ->quantum %u/%u", node->name, + node->info.id, str, max_quantum_size, + context->defaults.clock_rate); + node->max_quantum_size = max_quantum_size; + do_recalc = true; + } + } + } + pw_log_debug(NAME" %p: driver:%d recalc:%d active:%d", node, node->driver, do_recalc, node->active); diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index 1732e8ea1..73e438ad1 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -143,6 +143,8 @@ extern "C" { * node/session */ #define PW_KEY_NODE_LATENCY "node.latency" /**< the requested latency of the node as * a fraction. Ex: 128/48000 */ +#define PW_KEY_NODE_MAX_LATENCY "node.max-latency" /**< the maximum supported latency of the + * node as a fraction. Ex: 1024/48000 */ #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 */ #define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */ diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 4c3140300..3bb5d0a75 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -657,6 +657,8 @@ struct pw_impl_node { struct spa_fraction latency; /**< requested latency */ uint32_t quantum_size; /**< desired quantum */ + struct spa_fraction max_latency; /**< miximum latency */ + uint32_t max_quantum_size; /**< max supported quantum */ struct spa_source source; /**< source to remotely trigger this node */ struct pw_memblock *activation; struct {