From 97db4a68a7b98f42c207d6cfb0a0c1ee5c907443 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 27 Jan 2024 13:00:03 +0200 Subject: [PATCH] doc: explain clock/latency more Update SPA_IO_Clock/Position documentation. Explain some IOs are currently unused in PW. Explain meaning of latency. --- spa/include/spa/node/io.h | 73 +++++++++++++++++++++++---------- spa/include/spa/param/latency.h | 31 +++++++++++--- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/spa/include/spa/node/io.h b/spa/include/spa/node/io.h index c0777d3ba..bde1b6202 100644 --- a/spa/include/spa/node/io.h +++ b/spa/include/spa/node/io.h @@ -31,14 +31,15 @@ extern "C" { enum spa_io_type { SPA_IO_Invalid, SPA_IO_Buffers, /**< area to exchange buffers, struct spa_io_buffers */ - SPA_IO_Range, /**< expected byte range, struct spa_io_range */ + SPA_IO_Range, /**< expected byte range, struct spa_io_range (currently not used in PipeWire) */ SPA_IO_Clock, /**< area to update clock information, struct spa_io_clock */ - SPA_IO_Latency, /**< latency reporting, struct spa_io_latency */ + SPA_IO_Latency, /**< latency reporting, struct spa_io_latency (currently not used in + * PipeWire). \see spa_param_latency */ SPA_IO_Control, /**< area for control messages, struct spa_io_sequence */ SPA_IO_Notify, /**< area for notify messages, struct spa_io_sequence */ SPA_IO_Position, /**< position information in the graph, struct spa_io_position */ SPA_IO_RateMatch, /**< rate matching between nodes, struct spa_io_rate_match */ - SPA_IO_Memory, /**< memory pointer, struct spa_io_memory */ + SPA_IO_Memory, /**< memory pointer, struct spa_io_memory (currently not used in PipeWire) */ }; /** @@ -108,28 +109,47 @@ struct spa_io_range { * * The clock counts the elapsed time according to the clock provider * since the provider was last started. + * + * Driver nodes are supposed to update the contents of \ref SPA_IO_Clock before + * signaling the start of a graph cycle. These updated clock values become + * visible to other nodes in \ref SPA_IO_Position. Non-driver nodes do + * not need to update the contents of their \ref SPA_IO_Clock. + * + * The host generally gives each node a separate \ref spa_io_clock in \ref + * SPA_IO_Clock, so that updates made by the driver are not visible in the + * contents of \ref SPA_IO_Clock of other nodes. Instead, \ref SPA_IO_Position + * is used to look up the current graph time. + * + * A node is a driver when \ref spa_io_clock.id in \ref SPA_IO_Clock and + * \ref spa_io_position.clock.id in \ref SPA_IO_Position are the same. */ struct spa_io_clock { #define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0) - uint32_t flags; /**< clock flags */ - uint32_t id; /**< unique clock id, set by application */ - char name[64]; /**< clock name prefixed with API, set by node. The clock name - * is unique per clock and can be used to check if nodes - * share the same clock. */ - uint64_t nsec; /**< time in nanoseconds against monotonic clock */ - struct spa_fraction rate; /**< rate for position/duration/delay/xrun */ - uint64_t position; /**< current position */ - uint64_t duration; /**< duration of current cycle */ - int64_t delay; /**< delay between position and hardware */ - double rate_diff; /**< rate difference between clock and monotonic time */ - uint64_t next_nsec; /**< estimated next wakeup time in nanoseconds */ + 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 + * \ref SPA_IO_Clock. The clock name is unique per clock and + * can be used to check if nodes share the same clock. */ + uint64_t nsec; /**< Time in nanoseconds against monotonic clock + * (CLOCK_MONOTONIC). This fields reflects a real time instant + * in the past. The value may have jitter. */ + struct spa_fraction rate; /**< Rate for position/duration/delay/xrun */ + uint64_t position; /**< Current position, in samples @ \ref rate */ + uint64_t duration; /**< Duration of current cycle, in samples @ \ref rate */ + int64_t delay; /**< Delay between position and hardware, in samples @ \ref rate */ + double rate_diff; /**< Rate difference between clock and monotonic time, as a ratio of + * clock speeds. */ + uint64_t next_nsec; /**< Estimated next wakeup time in nanoseconds. + * This time is a logical start time of the next cycle, and + * is not necessarily in the future. + */ - struct spa_fraction target_rate; /**< target rate of next cycle */ - uint64_t target_duration; /**< target duration of next cycle */ - uint32_t target_seq; /**< seq counter. must be equal at start and + struct spa_fraction target_rate; /**< Target rate of next cycle */ + uint64_t target_duration; /**< Target duration of next cycle */ + uint32_t target_seq; /**< Seq counter. must be equal at start and * end of read and lower bit must be 0 */ uint32_t padding; - uint64_t xrun; /**< estimated accumulated xrun duration */ + uint64_t xrun; /**< Estimated accumulated xrun duration */ }; /* the size of the video in this cycle */ @@ -144,7 +164,11 @@ struct spa_io_video_size { uint32_t padding[4]; }; -/** latency reporting */ +/** + * Latency reporting + * + * Currently not used in PipeWire. Instead, \see spa_param_latency + */ struct spa_io_latency { struct spa_fraction rate; /**< rate for min/max */ uint64_t min; /**< min latency */ @@ -244,8 +268,13 @@ enum spa_io_position_state { /** * The position information adds extra meaning to the raw clock times. * - * It is set on all nodes and the clock id will contain the clock of the - * driving node in the graph. + * It is set on all nodes in \ref SPA_IO_Position, and the contents of \ref + * spa_io_position.clock contain the clock updates made by the driving node in + * the graph in its \ref SPA_IO_Clock. Also, \ref spa_io_position.clock.id + * will contain the clock id of the driving node in the graph. + * + * The position clock indicates the logical start time of the current graph + * cycle. * * The position information contains 1 or more segments that convert the * raw clock times to a stream time. They are sorted based on their diff --git a/spa/include/spa/param/latency.h b/spa/include/spa/param/latency.h index 65d001c2e..61a54fc2d 100644 --- a/spa/include/spa/param/latency.h +++ b/spa/include/spa/param/latency.h @@ -16,14 +16,30 @@ extern "C" { #include -/** properties for SPA_TYPE_OBJECT_ParamLatency */ +/** + * Properties for SPA_TYPE_OBJECT_ParamLatency + * + * The latency indicates: + * + * - for playback: time delay between start of a graph cycle, and the rendering of + * the first sample of that cycle in audio output. + * + * - for capture: time delay between start of a graph cycle, and the first sample + * of that cycle having occurred in audio input. + * + * For physical output/input, the latency is intended to correspond to the + * rendering/capture of physical audio. However, hardware internal rendering delay is + * usually not included e.g. for ALSA. + * + * The latency values are adjusted by \ref SPA_PROP_latencyOffsetNsec if present. + */ enum spa_param_latency { SPA_PARAM_LATENCY_START, SPA_PARAM_LATENCY_direction, /**< direction, input/output (Id enum spa_direction) */ SPA_PARAM_LATENCY_minQuantum, /**< min latency relative to quantum (Float) */ SPA_PARAM_LATENCY_maxQuantum, /**< max latency relative to quantum (Float) */ - SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to rate */ - SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to rate */ + SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to graph rate */ + SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to graph rate */ SPA_PARAM_LATENCY_minNs, /**< min latency (Long) in nanoseconds */ SPA_PARAM_LATENCY_maxNs, /**< max latency (Long) in nanoseconds */ }; @@ -41,11 +57,16 @@ struct spa_latency_info { #define SPA_LATENCY_INFO(dir,...) ((struct spa_latency_info) { .direction = (dir), ## __VA_ARGS__ }) -/** properties for SPA_TYPE_OBJECT_ParamProcessLatency */ +/** + * Properties for SPA_TYPE_OBJECT_ParamProcessLatency + * + * The processing latency indicates logical time delay between a sample in an input port, + * and a corresponding sample in an output port, relative to the graph time. + */ enum spa_param_process_latency { SPA_PARAM_PROCESS_LATENCY_START, SPA_PARAM_PROCESS_LATENCY_quantum, /**< latency relative to quantum (Float) */ - SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to rate */ + SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to graph rate */ SPA_PARAM_PROCESS_LATENCY_ns, /**< latency (Long) in nanoseconds */ };