|
libfunnel
|
libfunnel core API More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Data Structures | |
| struct | funnel_fraction |
| A rational frame rate. More... | |
Typedefs | |
| typedef struct funnel_ctx | funnel_ctx |
| A libfunnel context. | |
| typedef struct funnel_stream | funnel_stream |
| A PipeWire video stream. | |
| typedef struct funnel_buffer | funnel_buffer |
| A video buffer (frame). | |
| typedef void(* | funnel_buffer_callback) (void *opaque, struct funnel_stream *stream, struct funnel_buffer *buf) |
| A user callback for buffer creation/destruction. | |
Enumerations | |
| enum | funnel_mode { FUNNEL_ASYNC , FUNNEL_DOUBLE_BUFFERED , FUNNEL_SINGLE_BUFFERED , FUNNEL_SYNCHRONOUS } |
| Synchronization modes for the frame pacing. More... | |
| enum | funnel_sync { FUNNEL_SYNC_IMPLICIT , FUNNEL_SYNC_EXPLICIT , FUNNEL_SYNC_BOTH } |
| Buffer synchronization modes for frames. More... | |
| enum | funnel_stream_state { FUNNEL_STREAM_STATE_UNCONNECTED = 0 , FUNNEL_STREAM_STATE_CONNECTING = 1 , FUNNEL_STREAM_STATE_PAUSED = 2 , FUNNEL_STREAM_STATE_STREAMING = 3 } |
| Represents the state of a stream. More... | |
Functions | |
| static struct funnel_fraction | FUNNEL_FRACTION (uint32_t num, uint32_t den) |
| Helper to create a funnel_fraction. | |
| int | funnel_init (struct funnel_ctx **pctx) |
| Initialize a Funnel context. | |
| int | funnel_new (struct funnel_ctx **pctx) |
| Create a Funnel context. | |
| int | funnel_set_app_name (struct funnel_ctx *ctx, const char *app_name) |
| Set the user-friendly application name. | |
| int | funnel_set_app_id (struct funnel_ctx *ctx, const char *app_id) |
| Set the application ID. | |
| int | funnel_set_app_version (struct funnel_ctx *ctx, const char *app_version) |
| Set the application version. | |
| int | funnel_connect (struct funnel_ctx *ctx) |
| Connect to PipeWire. | |
| void | funnel_shutdown (struct funnel_ctx *ctx) |
| Shut down a Funnel context. | |
| int | funnel_stream_create (struct funnel_ctx *ctx, const char *name, struct funnel_stream **pstream) |
| Create a new stream. | |
| void | funnel_stream_set_buffer_callbacks (struct funnel_stream *stream, funnel_buffer_callback alloc, funnel_buffer_callback free, void *opaque) |
| Specify callbacks for buffer creation/destruction. | |
| int | funnel_stream_set_instance (struct funnel_stream *stream, const char *instance, bool user_friendly) |
| Set the instance for this stream. | |
| int | funnel_stream_set_unique_id (struct funnel_stream *stream, const char *stream_id) |
| Set the unique ID for this stream. | |
| int | funnel_stream_set_description (struct funnel_stream *stream, const char *description) |
| Set the description for this stream. | |
| int | funnel_stream_set_media_name (struct funnel_stream *stream, const char *media_name) |
| Set the media name for this stream. | |
| int | funnel_stream_set_size (struct funnel_stream *stream, uint32_t width, uint32_t height) |
| Set the frame dimensions for a stream. | |
| int | funnel_stream_set_mode (struct funnel_stream *stream, enum funnel_mode mode) |
| Configure the queueing mode for the stream. | |
| int | funnel_stream_set_sync (struct funnel_stream *stream, enum funnel_sync frontend, enum funnel_sync backend) |
| Configure the synchronization modes for the stream. | |
| int | funnel_stream_set_rate (struct funnel_stream *stream, struct funnel_fraction def, struct funnel_fraction min, struct funnel_fraction max) |
| Set the frame rate of a stream. | |
| int | funnel_stream_get_rate (struct funnel_stream *stream, struct funnel_fraction *prate) |
| Get the currently negotiated frame rate of a stream. | |
| void | funnel_stream_clear_formats (struct funnel_stream *stream) |
| Clear the supported format list. | |
| int | funnel_stream_configure (struct funnel_stream *stream) |
| Apply the stream configuration and register the stream with PipeWire. | |
| int | funnel_stream_start (struct funnel_stream *stream) |
| Start running a stream. | |
| int | funnel_stream_stop (struct funnel_stream *stream) |
| Stop running a stream. | |
| int | funnel_stream_get_state (struct funnel_stream *stream, enum funnel_stream_state *pstate) |
| Get the current state of a stream. | |
| void | funnel_stream_destroy (struct funnel_stream *stream) |
| Destroy a stream. | |
| int | funnel_stream_dequeue (struct funnel_stream *stream, struct funnel_buffer **pbuf) |
| Dequeue a buffer from a stream. | |
| int | funnel_stream_enqueue (struct funnel_stream *stream, struct funnel_buffer *buf) |
| Enqueue a buffer to a stream. | |
| int | funnel_stream_return (struct funnel_stream *stream, struct funnel_buffer *buf) |
| Return a buffer to the pool without enqueueing it. | |
| int | funnel_stream_skip_frame (struct funnel_stream *stream) |
| Break out of a frame processing cycle for a stream. | |
| void | funnel_buffer_get_size (struct funnel_buffer *buf, uint32_t *pwidth, uint32_t *pheight) |
| Get the dimensions of a Funnel buffer. | |
| void | funnel_buffer_set_user_data (struct funnel_buffer *buf, void *opaque) |
| Set an arbitrary user data pointer for a buffer. | |
| void * | funnel_buffer_get_user_data (struct funnel_buffer *buf) |
| Get an arbitrary user data pointer for a buffer. | |
| bool | funnel_buffer_has_sync (struct funnel_buffer *buf) |
| Check whether a buffer requires explicit synchronization. | |
| bool | funnel_buffer_is_efficient_for_rendering (struct funnel_buffer *buf) |
| Return whether a buffer is considered efficient for rendering. | |
Variables | |
| static const struct funnel_fraction | FUNNEL_RATE_VARIABLE = {0, 1} |
| Indicates that the frame rate is variable. | |
libfunnel core API
| typedef struct funnel_ctx funnel_ctx |
A libfunnel context.
As libfunnel uses no global state, each libfunnel context is completely independent. A context encapsulates a connection to the PipeWire daemon and a background processing thread that handles all PipeWire events and communication.
| typedef struct funnel_stream funnel_stream |
A PipeWire video stream.
A stream encapsulates a PipeWire node and a single output port. A stream can be configured with a given resolution and choice of formats. When it is connected to an input port, it will deliver frames to it.
A libfunnel context can have multiple streams, which all are managed through the shared PipeWire daemon connection and which share the same thread loop.
| typedef struct funnel_buffer funnel_buffer |
A video buffer (frame).
A buffer encapsulates a video frame of a given format and dimensions. Buffers are dynamically allocated and re-allocated when a stream negotiates its format and properties, as needed by the consumer it is connected to, or when the producer changes the stream confiiguration.
Buffers are allocated and owned by a stream and are re-used while video is being delivered. Buffers are either empty (ready for use), dequeued (owned by the API user, and being rendered or written to), or enqueued (ready for use and delivery to the consumer). When the consumer is done with a buffer, it is returned to libfunnel and becomes empty again.
Since the stream can re-negotiate at any time (through the background thread), a dequeued buffer might become invalid as new buffers were allocated. If this happens, the dequeued buffer is not freed immediately, so it can still be written or rendered to as normal. When such a stale buffer is enqueued, it will be discarded and freed instead.
| typedef void(* funnel_buffer_callback) (void *opaque, struct funnel_stream *stream, struct funnel_buffer *buf) |
A user callback for buffer creation/destruction.
| opaque | Opaque user data pointer |
| stream | Stream for this buffer [Lifetime: borrowed] |
| buf | Buffer being allocated or freed [Lifetime: borrowed] |
| enum funnel_mode |
Synchronization modes for the frame pacing.
| Enumerator | |
|---|---|
| FUNNEL_ASYNC | Produce frames asynchronously to the consumer. In this mode, libfunnel calls never block and you must be able to handle the lack of a buffer (by skipping rendering/copying to it). This mode only makes sense if your application is FPS-limited by some other consumer (for example, if it renders to the screen, usually with VSync). You should configure the frame rate you expect to produce frames at with funnel_stream_set_rate(). This mode essentially behaves like triple buffering. Whenever the PipeWire cycle runs, the consumer will receive the frame that was most recently submitted to funnel_stream_enqueue(). |
| FUNNEL_DOUBLE_BUFFERED | Produce frames synchronously to the consumer with double buffering. In this mode, after a frame is produced, it is queued to be sent out to the consumer in the next PipeWire process cycle, and you may immediately dequeue a new buffer to start rendering the next frame. libfunnel will block at funnel_stream_enqueue() until the previously queued frame has been consumed. In this mode, funnel_stream_dequeue() will only block if there are no free buffers (if the consumer is not freeing buffers quickly enough). This mode effectively adds two frames of latency, as up to two frames can be rendered ahead of the PipeWire cycle (one ready to be submitted, and one blocked at funnel_stream_enqueue()). |
| FUNNEL_SINGLE_BUFFERED | Produce frames synchronously to the consumer with single buffering. In this mode, after a frame is produced, it is queued to be sent out to the consumer in the next PipeWire process cycle. When you are ready to begin rendering a new frame, libfunnel will block at funnel_stream_dequeue() until the previous frame has been sent to the consumer. In this mode, funnel_stream_enqueue() will never block. This mode effectively adds one frame of latency, as only one frame can be rendered ahead of the PipeWire cycle. |
| FUNNEL_SYNCHRONOUS | Produce frames synchronously with the PipeWire process cycle. In this mode, funnel_stream_dequeue() will wait for the beginning of a PipeWire process cycle, and the process cycle will be blocked until the frame is submitted with funnel_stream_enqueue(). This mode provides the lowest possible latency, but is only suitable for applications that do not do much work to render frames (for example, just a copy), as the PipeWire graph will be blocked while the buffer is dequeued. It adds no latency. |
| enum funnel_sync |
Buffer synchronization modes for frames.
See Buffer synchronization for more information on sync modes.
| Enumerator | |
|---|---|
| FUNNEL_SYNC_IMPLICIT | Use implicit sync only. |
| FUNNEL_SYNC_EXPLICIT | Use explicit sync only. |
| FUNNEL_SYNC_BOTH | Support both implicit and explicit sync. |
| enum funnel_stream_state |
Represents the state of a stream.
This maps to a PipeWire pw_stream_state.
|
inlinestatic |
Helper to create a funnel_fraction.
| num | Numerator |
| den | Denominator |
| int funnel_init | ( | struct funnel_ctx ** | pctx | ) |
Initialize a Funnel context.
This is equivalent to funnel_create() followed by funnel_connect().
| [out] | pctx | New context [Lifetime: owned] |
| -ECONNREFUSED | Failed to connect to PipeWire daemon |
| -EIO | Fatal error connecting to PipeWire daemon |
| -EOPNOTSUPP | PipeWire daemon version is too old |
| int funnel_new | ( | struct funnel_ctx ** | pctx | ) |
Create a Funnel context.
As multiple Funnel contexts are completely independent, this function has no synchronization requirements.
| [out] | pctx | New context [Lifetime: owned] |
| int funnel_set_app_name | ( | struct funnel_ctx * | ctx, |
| const char * | app_name ) |
Set the user-friendly application name.
This should be the name of your application. It defaults to the process name.
This cannot be changed after the context is connected.
| ctx | Context [Lifetime: borrowed] |
| app_name | Application name [Lifetime: borrowed] |
| -EINVAL |
|
| int funnel_set_app_id | ( | struct funnel_ctx * | ctx, |
| const char * | app_id ) |
Set the application ID.
This should be the a unique ID for your application, such as a Flatpak reverse-DNS style ID.
This cannot be changed after the context is connected.
| ctx | Context [Lifetime: borrowed] |
| app_id | Application ID [Lifetime: borrowed] |
| -EINVAL |
|
| int funnel_set_app_version | ( | struct funnel_ctx * | ctx, |
| const char * | app_version ) |
Set the application version.
A version number, such as "1.2.3".
This cannot be changed after the context is connected.
| ctx | Context [Lifetime: borrowed] |
| app_version | Application version [Lifetime: borrowed] |
| -EINVAL |
|
| int funnel_connect | ( | struct funnel_ctx * | ctx | ) |
Connect to PipeWire.
| ctx | Context [Lifetime: borrowed] |
| -EINVAL | The context is already connected to PipeWire |
| -ECONNREFUSED | Failed to connect to PipeWire daemon |
| -EIO | Fatal error connecting to PipeWire daemon |
| -EOPNOTSUPP | PipeWire daemon version is too old |
| void funnel_shutdown | ( | struct funnel_ctx * | ctx | ) |
Shut down a Funnel context.
| ctx | Context [Lifetime: owned] |
| int funnel_stream_create | ( | struct funnel_ctx * | ctx, |
| const char * | name, | ||
| struct funnel_stream ** | pstream ) |
Create a new stream.
| ctx | Context [Lifetime: borrowed] | |
| name | Name of the new stream [Lifetime: borrowed] | |
| [out] | pstream | New stream [Lifetime: owned]-from{ctx} |
| -EINVAL | The context has not been connected to PipeWire yet |
| -EIO | The PipeWire context is invalid (fatal error) |
| void funnel_stream_set_buffer_callbacks | ( | struct funnel_stream * | stream, |
| funnel_buffer_callback | alloc, | ||
| funnel_buffer_callback | free, | ||
| void * | opaque ) |
Specify callbacks for buffer creation/destruction.
| stream | Stream [Lifetime: borrowed] |
| alloc | Callback when a buffer is allocated [Lifetime: borrowed-by stream] |
| free | Callback when a buffer is freed [Lifetime: borrowed-by stream] |
| opaque | Opaque user pointer |
| int funnel_stream_set_instance | ( | struct funnel_stream * | stream, |
| const char * | instance, | ||
| bool | user_friendly ) |
Set the instance for this stream.
This should be an identifier to tell apart multiple instances of your application, if it supports multiple concurrent instances (or multiple "documents"). It should be persistent. For example, you can use the "project"/"file" name the user is working with.
Do not use a volatile ID such as the process ID, as that will break auto-connection on restart.
If you do not have anything that could be used for this purpose, then you must either allow it to be user-configurable, or leave the instance name unset and instead make sure that the stream name is user-configurable, so that users can ensure that streams across multiple instances of your application can always be uniquely identified.
This cannot be changed after the stream is first configured.
| stream | Stream [Lifetime: borrowed] |
| instance | Instance identifier [Lifetime: borrowed] |
| user_friendly | Whether the instance name is "user friendly" and should be included in the default description. |
| -EINVAL |
|
| int funnel_stream_set_unique_id | ( | struct funnel_stream * | stream, |
| const char * | stream_id ) |
Set the unique ID for this stream.
This should be a persistent, unique ID within your instance. It defaults to the stream name, with special characters removed. For example, this could be a UUID if you have such an internal unique identifier for the stream.
This cannot be changed after the stream is first configured.
| stream | Stream [Lifetime: borrowed] |
| stream_id | Stream ID [Lifetime: borrowed] |
| -EINVAL |
|
| int funnel_stream_set_description | ( | struct funnel_stream * | stream, |
| const char * | description ) |
Set the description for this stream.
This should be a user-friendly description.
Defaults to an automatically generated string using the application name, instance name (if friendly), and stream name.
This cannot be changed after the stream is first configured.
| stream | Stream [Lifetime: borrowed] |
| description | Stream description [Lifetime: borrowed] |
| -EINVAL |
|
| int funnel_stream_set_media_name | ( | struct funnel_stream * | stream, |
| const char * | media_name ) |
Set the media name for this stream.
Unlike the other name properties, this can be changed while the stream is running. For example, when a stream is playing back a particular video content, the media name can reflect that to the user (e.g. the name of a movie).
Call funnel_stream_configure() after this to update the stream.
Defaults to the stream name.
| stream | Stream [Lifetime: borrowed] |
| media_name | Media name [Lifetime: borrowed] |
| -EINVAL | Invalid argument |
| int funnel_stream_set_size | ( | struct funnel_stream * | stream, |
| uint32_t | width, | ||
| uint32_t | height ) |
Set the frame dimensions for a stream.
| stream | Stream [Lifetime: borrowed] |
| width | Width in pixels |
| height | Height in pixels |
| -EINVAL | Invalid argument |
| int funnel_stream_set_mode | ( | struct funnel_stream * | stream, |
| enum funnel_mode | mode ) |
Configure the queueing mode for the stream.
| stream | Stream [Lifetime: borrowed] |
| mode | Queueing mode for the stream |
| -EINVAL | Invalid argument |
| int funnel_stream_set_sync | ( | struct funnel_stream * | stream, |
| enum funnel_sync | frontend, | ||
| enum funnel_sync | backend ) |
Configure the synchronization modes for the stream.
See Buffer synchronization for more information on sync modes.
| stream | Stream [Lifetime: borrowed] |
| frontend | Synchronization mode for the libfunnel API |
| backend | Synchronization mode for the PipeWire stream |
| -EINVAL | The selected sync combination is invalid for this API |
| -EOPNOTSUPP | The API/driver does not support this sync mode |
| int funnel_stream_set_rate | ( | struct funnel_stream * | stream, |
| struct funnel_fraction | def, | ||
| struct funnel_fraction | min, | ||
| struct funnel_fraction | max ) |
Set the frame rate of a stream.
Note: If the default rate is FUNNEL_RATE_VARIABLE, then the minimum rate also needs to be FUNNEL_RATE_VARIABLE. Otherwise, this will cause issues with some PipeWire versions.
| stream | Stream [Lifetime: borrowed] |
| def | Default frame rate (FUNNEL_RATE_VARIABLE for no default or variable) |
| min | Minimum frame rate (FUNNEL_RATE_VARIABLE if variable) |
| max | Maximum frame rate (FUNNEL_RATE_VARIABLE if variable) |
| -EINVAL | Invalid argument |
| int funnel_stream_get_rate | ( | struct funnel_stream * | stream, |
| struct funnel_fraction * | prate ) |
Get the currently negotiated frame rate of a stream.
| stream | Stream [Lifetime: borrowed] | |
| [out] | prate | Output frame rate |
| -EINPROGRESS | The stream is not yet initialized |
| void funnel_stream_clear_formats | ( | struct funnel_stream * | stream | ) |
Clear the supported format list.
Used for reconfiguration.
| stream | Stream [Lifetime: borrowed] |
| int funnel_stream_configure | ( | struct funnel_stream * | stream | ) |
Apply the stream configuration and register the stream with PipeWire.
If called on an already configured stream, this will update the configuration.
| stream | Stream [Lifetime: borrowed] |
| -EINVAL | The stream is in an invalid state (missing settings) |
| -EIO | The PipeWire context is invalid or stream creation failed |
| int funnel_stream_start | ( | struct funnel_stream * | stream | ) |
Start running a stream.
| stream | Stream [Lifetime: borrowed] |
| -EINVAL | The stream is in an invalid state (not configured) |
| -EIO | The PipeWire context is invalid or stream creation failed |
| int funnel_stream_stop | ( | struct funnel_stream * | stream | ) |
Stop running a stream.
If another thread is blocked on funnel_stream_dequeue(), this will unblock it.
| stream | Stream [Lifetime: borrowed] |
| -EINVAL | The stream is not started |
| -EIO | The PipeWire context is invalid |
| int funnel_stream_get_state | ( | struct funnel_stream * | stream, |
| enum funnel_stream_state * | pstate ) |
Get the current state of a stream.
This is primarily intended for informational purposes (for user feedback). It could also be used to change the rendering flow depending on whether the stream is expected to consume frames or not. The return value should be treated as a hint.
NOTE: This function should not be used to make any decisions about blocking calls! Since the stream state may change at any time, a running stream could transition to the paused state immediately after this call returns. Similarly, calling funnel_stream_dequeue() immediately after this call could return a buffer even if the stream is paused, or might not return a buffer despite the stream being running.
| stream | Stream [Lifetime: borrowed] | |
| [out] | pstate | The returned stream state |
| -EIO |
|
| void funnel_stream_destroy | ( | struct funnel_stream * | stream | ) |
Destroy a stream.
The stream will be stopped if it is running.
| stream | Stream [Lifetime: owned] |
| int funnel_stream_dequeue | ( | struct funnel_stream * | stream, |
| struct funnel_buffer ** | pbuf ) |
Dequeue a buffer from a stream.
Note that, currently, you may only have one buffer dequeued at a time.
| stream | Stream [Lifetime: borrowed] | |
| [out] | pbuf | Buffer that was dequeued [Lifetime: owned]-from{stream} |
| 0 | No buffer is available |
| 1 | A buffer was successfully dequeued |
| -EINVAL | Stream is in an invalid state |
| -EBUSY | Attempted to dequeue more than one buffer at once |
| -EIO | The PipeWire context is invalid |
| -ESHUTDOWN | Stream is not started |
| int funnel_stream_enqueue | ( | struct funnel_stream * | stream, |
| struct funnel_buffer * | buf ) |
Enqueue a buffer to a stream.
After this call, the buffer is no longer owned by the user and may not be queued again until it is dequeued.
| stream | Stream [Lifetime: borrowed] |
| buf | Buffer to enqueue [Lifetime: owned] |
| 0 | The buffer was dropped because the stream configuration or state changed. |
| 1 | The buffer was successfully enqueued. |
| -EINVAL |
|
| int funnel_stream_return | ( | struct funnel_stream * | stream, |
| struct funnel_buffer * | buf ) |
Return a buffer to the pool without enqueueing it.
After this call, the buffer is no longer owned by the user and may not be queued again until it is dequeued. This will effectively drop one frame in the stream (a PipeWire process cycle will complete with no frame transfer).
| stream | Stream [Lifetime: borrowed] |
| buf | Buffer to return [Lifetime: owned] |
| -EINVAL |
|
| int funnel_stream_skip_frame | ( | struct funnel_stream * | stream | ) |
Break out of a frame processing cycle for a stream.
This call unblocks stream buffer enqueue/dequeue functions. This is useful to break a thread out of blocking calls. The precise behavior depends on the mode:
Note that this function does not force an empty PipeWire process cycle, that is, it won't "skip a frame" in the stream itself. Think of it as skipping a frame loop from the point of view of your code. In other words, it does not forcefully generate any delay.
| stream | Stream [Lifetime: borrowed] |
| -EINVAL | Stream is in an invalid state (not yet configured) |
| void funnel_buffer_get_size | ( | struct funnel_buffer * | buf, |
| uint32_t * | pwidth, | ||
| uint32_t * | pheight ) |
Get the dimensions of a Funnel buffer.
| buf | Buffer [Lifetime: borrowed] | |
| [out] | pwidth | Output width |
| [out] | pheight | Output height |
| void funnel_buffer_set_user_data | ( | struct funnel_buffer * | buf, |
| void * | opaque ) |
Set an arbitrary user data pointer for a buffer.
The user is responsible for managing the lifetime of this object. Generally, you should use funnel_stream_set_buffer_callbacks() to provide buffer creation/destruction callbacks, and set and release the user data pointer in the alloc and free callback respectively.
| buf | Buffer [Lifetime: borrowed] |
| opaque | Opaque user data pointer |
| void * funnel_buffer_get_user_data | ( | struct funnel_buffer * | buf | ) |
Get an arbitrary user data pointer for a buffer.
| buf | Buffer [Lifetime: borrowed] |
| bool funnel_buffer_has_sync | ( | struct funnel_buffer * | buf | ) |
Check whether a buffer requires explicit synchronization.
| buf | Buffer [Lifetime: borrowed] |
| true | if the buffer requires explicit synchronization |
| bool funnel_buffer_is_efficient_for_rendering | ( | struct funnel_buffer * | buf | ) |
Return whether a buffer is considered efficient for rendering.
Buffers are considered efficient when they are not using linear tiling and non-linear tiling is supported by the GPU driver.
| buf | Buffer [Lifetime: borrowed] |
| true | if the buffer is likely to be efficient to render into |
| false | if the buffer is unlikely to be efficient to render into |