| /* Simple Plugin API */ | |
| /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ | |
| /* SPDX-License-Identifier: MIT */ | |
| #ifndef SPA_IO_H | |
| #define SPA_IO_H | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| /** | |
| * \addtogroup spa_node | |
| * \{ | |
| */ | |
| #include <spa/utils/defs.h> | |
| #include <spa/pod/pod.h> | |
| /** IO areas | |
| * | |
| * IO information for a port on a node. This is allocated | |
| * by the host and configured on a node or all ports for which | |
| * IO is requested. | |
| * | |
| * The plugin will communicate with the host through the IO | |
| * areas. | |
| */ | |
| /** Different IO area types */ | |
| 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 (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 (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 (currently not used in PipeWire) */ | |
| SPA_IO_AsyncBuffers, /**< async area to exchange buffers, struct spa_io_async_buffers */ | |
| }; | |
| /** | |
| * IO area to exchange buffers. | |
| * | |
| * A set of buffers should first be configured on the node/port. | |
| * Further references to those buffers will be made by using the | |
| * id of the buffer. | |
| * | |
| * If status is SPA_STATUS_OK, the host should ignore | |
| * the io area. | |
| * | |
| * If status is SPA_STATUS_NEED_DATA, the host should: | |
| * 1) recycle the buffer in buffer_id, if possible | |
| * 2) prepare a new buffer and place the id in buffer_id. | |
| * | |
| * If status is SPA_STATUS_HAVE_DATA, the host should consume | |
| * the buffer in buffer_id and set the state to | |
| * SPA_STATUS_NEED_DATA when new data is requested. | |
| * | |
| * If status is SPA_STATUS_STOPPED, some error occurred on the | |
| * port. | |
| * | |
| * If status is SPA_STATUS_DRAINED, data from the io area was | |
| * used to drain. | |
| * | |
| * Status can also be a negative errno value to indicate errors. | |
| * such as: | |
| * -EINVAL: buffer_id is invalid | |
| * -EPIPE: no more buffers available | |
| */ | |
| struct spa_io_buffers { | |
| #define SPA_STATUS_OK 0 | |
| #define SPA_STATUS_NEED_DATA (1<<0) | |
| #define SPA_STATUS_HAVE_DATA (1<<1) | |
| #define SPA_STATUS_STOPPED (1<<2) | |
| #define SPA_STATUS_DRAINED (1<<3) | |
| int32_t status; /**< the status code */ | |
| uint32_t buffer_id; /**< a buffer id */ | |
| }; | |
| #define SPA_IO_BUFFERS_INIT ((struct spa_io_buffers) { SPA_STATUS_OK, SPA_ID_INVALID, }) | |
| /** | |
| * IO area to exchange a memory region | |
| */ | |
| struct spa_io_memory { | |
| int32_t status; /**< the status code */ | |
| uint32_t size; /**< the size of \a data */ | |
| void *data; /**< a memory pointer */ | |
| }; | |
| #define SPA_IO_MEMORY_INIT ((struct spa_io_memory) { SPA_STATUS_OK, 0, NULL, }) | |
| /** A range, suitable for input ports that can suggest a range to output ports */ | |
| struct spa_io_range { | |
| uint64_t offset; /**< offset in range */ | |
| uint32_t min_size; /**< minimum size of data */ | |
| uint32_t max_size; /**< maximum size of data */ | |
| }; | |
| /** | |
| * Absolute time reporting. | |
| * | |
| * Nodes that can report clocking information will receive this io block. | |
| * The application sets the id. This is usually set as part of the | |
| * position information but can also be set separately. | |
| * | |
| * 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) /* 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 */ | |
| #define SPA_IO_CLOCK_FLAG_NO_RATE (1u<<3) /* the rate of the clock is only approximately. | |
| * it is recommended to use the nsec as a clock source. | |
| * The rate_diff contains the measured inaccuracy. */ | |
| 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 | |
| * end of read and lower bit must be 0 */ | |
| uint32_t cycle; /**< incremented each time the graph is started */ | |
| uint64_t xrun; /**< Estimated accumulated xrun duration */ | |
| }; | |
| /* the size of the video in this cycle */ | |
| struct spa_io_video_size { | |
| #define SPA_IO_VIDEO_SIZE_VALID (1<<0) | |
| uint32_t flags; /**< optional flags */ | |
| uint32_t stride; /**< video stride in bytes */ | |
| struct spa_rectangle size; /**< the video size */ | |
| struct spa_fraction framerate; /**< the minimum framerate, the cycle duration is | |
| * always smaller to ensure there is only one | |
| * video frame per cycle. */ | |
| uint32_t padding[4]; | |
| }; | |
| /** | |
| * 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 */ | |
| uint64_t max; /**< max latency */ | |
| }; | |
| /** control stream, io area for SPA_IO_Control and SPA_IO_Notify */ | |
| struct spa_io_sequence { | |
| struct spa_pod_sequence sequence; /**< sequence of timed events */ | |
| }; | |
| /** bar and beat segment */ | |
| struct spa_io_segment_bar { | |
| #define SPA_IO_SEGMENT_BAR_FLAG_VALID (1<<0) | |
| uint32_t flags; /**< extra flags */ | |
| uint32_t offset; /**< offset in segment of this beat */ | |
| float signature_num; /**< time signature numerator */ | |
| float signature_denom; /**< time signature denominator */ | |
| double bpm; /**< beats per minute */ | |
| double beat; /**< current beat in segment */ | |
| double bar_start_tick; | |
| double ticks_per_beat; | |
| uint32_t padding[4]; | |
| }; | |
| /** video frame segment */ | |
| struct spa_io_segment_video { | |
| #define SPA_IO_SEGMENT_VIDEO_FLAG_VALID (1<<0) | |
| #define SPA_IO_SEGMENT_VIDEO_FLAG_DROP_FRAME (1<<1) | |
| #define SPA_IO_SEGMENT_VIDEO_FLAG_PULL_DOWN (1<<2) | |
| #define SPA_IO_SEGMENT_VIDEO_FLAG_INTERLACED (1<<3) | |
| uint32_t flags; /**< flags */ | |
| uint32_t offset; /**< offset in segment */ | |
| struct spa_fraction framerate; | |
| uint32_t hours; | |
| uint32_t minutes; | |
| uint32_t seconds; | |
| uint32_t frames; | |
| uint32_t field_count; /**< 0 for progressive, 1 and 2 for interlaced */ | |
| uint32_t padding[11]; | |
| }; | |
| /** | |
| * A segment converts a running time to a segment (stream) position. | |
| * | |
| * The segment position is valid when the current running time is between | |
| * start and start + duration. The position is then | |
| * calculated as: | |
| * | |
| * (running time - start) * rate + position; | |
| * | |
| * Support for looping is done by specifying the LOOPING flags with a | |
| * non-zero duration. When the running time reaches start + duration, | |
| * duration is added to start and the loop repeats. | |
| * | |
| * Care has to be taken when the running time + clock.duration extends | |
| * past the start + duration from the segment; the user should correctly | |
| * wrap around and partially repeat the loop in the current cycle. | |
| * | |
| * Extra information can be placed in the segment by setting the valid flags | |
| * and filling up the corresponding structures. | |
| */ | |
| struct spa_io_segment { | |
| uint32_t version; | |
| #define SPA_IO_SEGMENT_FLAG_LOOPING (1<<0) /**< after the duration, the segment repeats */ | |
| #define SPA_IO_SEGMENT_FLAG_NO_POSITION (1<<1) /**< position is invalid. The position can be invalid | |
| * after a seek, for example, when the exact mapping | |
| * of the extra segment info (bar, video, ...) to | |
| * position has not been determined yet */ | |
| uint32_t flags; /**< extra flags */ | |
| uint64_t start; /**< value of running time when this | |
| * info is active. Can be in the future for | |
| * pending changes. It does not have to be in | |
| * exact multiples of the clock duration. */ | |
| uint64_t duration; /**< duration when this info becomes invalid expressed | |
| * in running time. If the duration is 0, this | |
| * segment extends to the next segment. If the | |
| * segment becomes invalid and the looping flag is | |
| * set, the segment repeats. */ | |
| double rate; /**< overall rate of the segment, can be negative for | |
| * backwards time reporting. */ | |
| uint64_t position; /**< The position when the running time == start. | |
| * can be invalid when the owner of the extra segment | |
| * information has not yet made the mapping. */ | |
| struct spa_io_segment_bar bar; | |
| struct spa_io_segment_video video; | |
| }; | |
| enum spa_io_position_state { | |
| SPA_IO_POSITION_STATE_STOPPED, | |
| SPA_IO_POSITION_STATE_STARTING, | |
| SPA_IO_POSITION_STATE_RUNNING, | |
| }; | |
| /** the maximum number of segments visible in the future */ | |
| #define SPA_IO_POSITION_MAX_SEGMENTS 8 | |
| /** | |
| * The position information adds extra meaning to the raw clock times. | |
| * | |
| * 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 | |
| * start times, and thus the order in which they will activate in | |
| * the future. This makes it possible to look ahead in the scheduled | |
| * segments and anticipate the changes in the timeline. | |
| */ | |
| struct spa_io_position { | |
| struct spa_io_clock clock; /**< clock position of driver, always valid and | |
| * read only */ | |
| struct spa_io_video_size video; /**< size of the video in the current cycle */ | |
| int64_t offset; /**< an offset to subtract from the clock position | |
| * to get a running time. This is the time that | |
| * the state has been in the RUNNING state and the | |
| * time that should be used to compare the segment | |
| * start values against. */ | |
| uint32_t state; /**< one of enum spa_io_position_state */ | |
| uint32_t n_segments; /**< number of segments */ | |
| struct spa_io_segment segments[SPA_IO_POSITION_MAX_SEGMENTS]; /**< segments */ | |
| }; | |
| /** | |
| * Rate matching. | |
| * | |
| * It is usually set on the nodes that process resampled data, by | |
| * the component (audioadapter) that handles resampling between graph | |
| * and node rates. The \a flags and \a rate fields may be modified by the node. | |
| * | |
| * The node can request a correction to the resampling rate in its process(), by setting | |
| * \ref SPA_IO_RATE_MATCH_ACTIVE on \a flags, and setting \a rate to the desired rate | |
| * correction. Usually the rate is obtained from DLL or other adaptive mechanism that | |
| * e.g. drives the node buffer fill level toward a specific value. | |
| * | |
| * When resampling to (graph->node) direction, the number of samples produced | |
| * by the resampler varies on each cycle, as the rates are not commensurate. | |
| * | |
| * When resampling to (node->graph) direction, the number of samples consumed by the | |
| * resampler varies. Node output ports in process() should produce \a size number of | |
| * samples to match what the resampler needs to produce one graph quantum of output | |
| * samples. | |
| * | |
| * Resampling filters introduce processing delay, given by \a delay and \a delay_frac, in | |
| * samples at node rate. The delay varies on each cycle e.g. when resampling between | |
| * noncommensurate rates. | |
| * | |
| * The first sample output (graph->node) or consumed (node->graph) by the resampler is | |
| * offset by \a delay + \a delay_frac / 1e9 node samples relative to the nominal graph | |
| * cycle start position: | |
| * | |
| * \code{.unparsed} | |
| * first_resampled_sample_nsec = | |
| * first_original_sample_nsec | |
| * - (rate_match->delay * SPA_NSEC_PER_SEC + rate_match->delay_frac) / node_rate | |
| * \endcode | |
| */ | |
| struct spa_io_rate_match { | |
| uint32_t delay; /**< resampling delay, in samples at | |
| * node rate */ | |
| uint32_t size; /**< requested input size for resampler */ | |
| double rate; /**< rate for resampler (set by node) */ | |
| #define SPA_IO_RATE_MATCH_FLAG_ACTIVE (1 << 0) | |
| uint32_t flags; /**< extra flags (set by node) */ | |
| int32_t delay_frac; /**< resampling delay fractional part, | |
| * in units of nanosamples (1/10^9 sample) at node rate */ | |
| uint32_t padding[6]; | |
| }; | |
| /** async buffers */ | |
| struct spa_io_async_buffers { | |
| struct spa_io_buffers buffers[2]; /**< async buffers, writers write to current (cycle+1)&1, | |
| * readers read from (cycle)&1 */ | |
| }; | |
| /** | |
| * \} | |
| */ | |
| #ifdef __cplusplus | |
| } /* extern "C" */ | |
| #endif | |
| #endif /* SPA_IO_H */ |