mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
keys: add lazy scheduling flags and docs
This commit is contained in:
parent
ae0dd9195a
commit
9c49bffc22
5 changed files with 154 additions and 0 deletions
|
|
@ -206,4 +206,143 @@ After they complete (and only when the profiler is active), they will trigger an
|
|||
extra eventfd to signal the server that the graph completed. This is used by the
|
||||
server to generate the profiler info.
|
||||
|
||||
## Lazy scheduling
|
||||
|
||||
Normally, a driver will wake up the graph and all the followers need to process
|
||||
the data in sync. There are cases where:
|
||||
|
||||
1. the follower might not be ready to process the data
|
||||
2. the driver rate is not ideal, the follower rate is better
|
||||
3. the driver might not know when new data is available in the follower and
|
||||
might wake up the graph too often.
|
||||
|
||||
In these cases, the driver and follower roles need to be reversed and a mechanism
|
||||
needs to be provided so that the follower can know when it is worth processing the
|
||||
graph.
|
||||
|
||||
For notifying when the graph is ready to be processed, (non driver) nodes can send
|
||||
a RequestProcess event which will arrive as a RequestProcess command in the driver.
|
||||
The driver can then decide to run the graph or not.
|
||||
|
||||
When the graph is started or partially controlled by RequestProcess events and
|
||||
commands we say we have lazy scheduling. The driver is not always scheduling according
|
||||
to its own rhythm but also depending on the follower.
|
||||
|
||||
We can't just enable lazy scheduling when no follower will emit RequestProcess events
|
||||
or when no driver will listen for RequestProcess commands. Two new node properties are
|
||||
defined:
|
||||
|
||||
- node.supports-lazy = 0 | 1 | ...
|
||||
|
||||
0 means lazy scheduling as a driver is not supported
|
||||
>1 means lazy scheduling as a driver is supported with increasing preference
|
||||
|
||||
- node.supports-request
|
||||
|
||||
0 means request events as a follower are not supported
|
||||
>1 means request events as a follower are supported with increasing preference
|
||||
|
||||
We can only enable lazy scheduling when both the driver and (at least one) follower
|
||||
has the node.supports-lazy and node.supports-request property respectively.
|
||||
|
||||
Node can end up as a driver (is_driver()) and lazy scheduling can be enabled (is_lazy()),
|
||||
which results in the following cases:
|
||||
|
||||
driver producer
|
||||
-> node.driver = true
|
||||
-> is_driving() && !is_lazy()
|
||||
-> calls trigger_process() to start the graph
|
||||
|
||||
lazy producer
|
||||
-> node.driver = true
|
||||
-> node.supports-lazy = 1
|
||||
-> is_driving() && is_lazy()
|
||||
-> listens for RequestProcess and calls trigger_process() to start the graph
|
||||
|
||||
requesting producer
|
||||
-> node.supports-request = 1
|
||||
-> !is_driving() && is_lazy()
|
||||
-> emits RequestProcess to suggest starting the graph
|
||||
|
||||
follower producer
|
||||
-> !is_driving() && !is_lazy()
|
||||
|
||||
|
||||
driver consumer
|
||||
-> node.driver = true
|
||||
-> is_driving() && !is_lazy()
|
||||
-> calls trigger_process() to start the graph
|
||||
|
||||
lazy consumer
|
||||
-> node.driver = true
|
||||
-> node.supports-lazy = 1
|
||||
-> is_driving() && is_lazy()
|
||||
-> listens for RequestProcess and calls trigger_process() to start the graph
|
||||
|
||||
requesting consumer
|
||||
-> node.supports-request = 1
|
||||
-> !is_driving() && is_lazy()
|
||||
-> emits RequestProcess to suggest starting the graph
|
||||
|
||||
follower consumer
|
||||
-> !is_driving() && !is_lazy()
|
||||
|
||||
|
||||
Some use cases:
|
||||
|
||||
1. Screensharing - driver producer, follower consumer
|
||||
- The producer starts the graph when a new frame is available.
|
||||
- The consumer consumes the new frames.
|
||||
-> throttles to the rate of the producer and idles when no frames
|
||||
are available.
|
||||
|
||||
producer
|
||||
- node.driver = true
|
||||
|
||||
consumer
|
||||
- node.driver = false
|
||||
|
||||
-> producer selected as driver, consumer is simple follower.
|
||||
lazy scheduling inactive (no lazy driver or no request follower)
|
||||
|
||||
|
||||
2. headless server - requesting producer, (semi) lazy driver consumer
|
||||
|
||||
- The producer emits RequestProcess when new frames are available.
|
||||
- The consumer requests new frames from the producer according to its
|
||||
refresh rate when there are RequestProcess commands.
|
||||
-> this throttles the framerate to the consumer but idles when there is
|
||||
no activity on the producer.
|
||||
|
||||
producer
|
||||
- node.driver = true
|
||||
- node.supports-request = 1
|
||||
|
||||
consumer
|
||||
- node.driver = true
|
||||
- node.supports-lazy = 2
|
||||
|
||||
-> consumer is selected as driver (lazy > request)
|
||||
lazy scheduling active (1 lazy driver and at least 1 request follower)
|
||||
|
||||
|
||||
3. frame encoder - lazy driver producer, requesting follower consumer
|
||||
|
||||
- The consumer pulls a frame when it is ready to encode the next one.
|
||||
- The producer produces the next frame on demand.
|
||||
-> throttles the speed to the consumer without idle.
|
||||
|
||||
producer
|
||||
- node.driver = true
|
||||
- node.supports-lazy = 1
|
||||
|
||||
consumer
|
||||
- node.driver = true
|
||||
- node.supports-request = 1
|
||||
|
||||
-> producer is selected as driver (lazy <= request)
|
||||
lazy scheduling active (1 lazy driver and at least 1 request follower)
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ struct spa_io_range {
|
|||
struct spa_io_clock {
|
||||
#define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0) /* graph is freewheeling */
|
||||
#define SPA_IO_CLOCK_FLAG_XRUN_RECOVER (1u<<1) /* recovering from xrun */
|
||||
#define SPA_IO_CLOCK_FLAG_LAZY (1u<<2) /* lazy scheduling */
|
||||
uint32_t flags; /**< Clock flags */
|
||||
uint32_t id; /**< Unique clock id, set by host application */
|
||||
char name[64]; /**< Clock name prefixed with API, set by node when it receives
|
||||
|
|
|
|||
|
|
@ -1123,6 +1123,8 @@ static void check_properties(struct pw_impl_node *node)
|
|||
recalc_reason = "driver priority changed";
|
||||
}
|
||||
}
|
||||
node->supports_lazy = pw_properties_get_uint32(node->properties, PW_KEY_NODE_SUPPORTS_LAZY, 0);
|
||||
node->supports_request = pw_properties_get_uint32(node->properties, PW_KEY_NODE_SUPPORTS_REQUEST, 0);
|
||||
|
||||
if ((str = pw_properties_get(node->properties, PW_KEY_NODE_NAME)) &&
|
||||
(node->name == NULL || !spa_streq(node->name, str))) {
|
||||
|
|
|
|||
|
|
@ -190,6 +190,15 @@ extern "C" {
|
|||
#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph. When the node is
|
||||
* selected as the driver, it needs to start
|
||||
* the graph periodically. */
|
||||
#define PW_KEY_NODE_SUPPORTS_LAZY "node.supports-lazy" /**< the node can be a lazy driver. It will listen
|
||||
* to RequestProcess commands and take them into
|
||||
* account when deciding to start the graph.
|
||||
* A value of 0 disables support, a value of > 0
|
||||
* enables with increasing preference. */
|
||||
#define PW_KEY_NODE_SUPPORTS_REQUEST "node.supports-request" /**< The node supports emiting RequestProcess events
|
||||
* when it wants the graph to be scheduled.
|
||||
* A value of 0 disables support, a value of > 0
|
||||
* enables with increasing preference. */
|
||||
#define PW_KEY_NODE_DRIVER_ID "node.driver-id" /**< the node id of the node assigned as driver
|
||||
* for this node */
|
||||
#define PW_KEY_NODE_ASYNC "node.async" /**< the node wants async scheduling */
|
||||
|
|
|
|||
|
|
@ -752,6 +752,9 @@ struct pw_impl_node {
|
|||
|
||||
char *name; /** for debug */
|
||||
|
||||
uint32_t supports_lazy; /**< lazy driver preference */
|
||||
uint32_t supports_request; /**< request follower preference */
|
||||
|
||||
uint32_t priority_driver; /** priority for being driver */
|
||||
char **groups; /** groups to schedule this node in */
|
||||
char **link_groups; /** groups this node is linked to */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue