summaryrefslogtreecommitdiffstats
path: root/third_party/pipewire/pipewire/stream.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/pipewire/pipewire/stream.h')
-rw-r--r--third_party/pipewire/pipewire/stream.h521
1 files changed, 521 insertions, 0 deletions
diff --git a/third_party/pipewire/pipewire/stream.h b/third_party/pipewire/pipewire/stream.h
new file mode 100644
index 0000000000..e61213dd0d
--- /dev/null
+++ b/third_party/pipewire/pipewire/stream.h
@@ -0,0 +1,521 @@
+/* PipeWire
+ *
+ * Copyright © 2018 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PIPEWIRE_STREAM_H
+#define PIPEWIRE_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \page page_streams Streams
+ *
+ * \section sec_overview Overview
+ *
+ * \ref pw_stream "Streams" are used to exchange data with the
+ * PipeWire server. A stream is a wrapper around a proxy for a pw_client_node
+ * with an adapter. This means the stream will automatically do conversion
+ * to the type required by the server.
+ *
+ * Streams can be used to:
+ *
+ * \li Consume a stream from PipeWire. This is a PW_DIRECTION_INPUT stream.
+ * \li Produce a stream to PipeWire. This is a PW_DIRECTION_OUTPUT stream
+ *
+ * You can connect the stream port to a specific server port or let PipeWire
+ * choose a port for you.
+ *
+ * For more complicated nodes such as filters or ports with multiple
+ * inputs and/or outputs you will need to use the pw_filter or make
+ * a pw_node yourself and export it with \ref pw_core_export.
+ *
+ * Streams can also be used to:
+ *
+ * \li Implement a Sink in PipeWire. This is a PW_DIRECTION_INPUT stream.
+ * \li Implement a Source in PipeWire. This is a PW_DIRECTION_OUTPUT stream
+ *
+ * In this case, the PW_KEY_MEDIA_CLASS property needs to be set to
+ * "Audio/Sink" or "Audio/Source" respectively.
+ *
+ * \section sec_create Create
+ *
+ * Make a new stream with \ref pw_stream_new(). You will need to specify
+ * a name for the stream and extra properties. The basic set of properties
+ * each stream must provide is filled in automatically.
+ *
+ * Once the stream is created, the state_changed event should be used to
+ * track the state of the stream.
+ *
+ * \section sec_connect Connect
+ *
+ * The stream is initially unconnected. To connect the stream, use
+ * \ref pw_stream_connect(). Pass the desired direction as an argument.
+ *
+ * The direction is:
+
+ * \li PW_DIRECTION_INPUT for a stream that *consumes* data. This can be a
+ * stream that captures from a Source or a when the stream is used to
+ * implement a Sink.
+ *
+ * \li PW_DIRECTION_OUTPUT for a stream that *produces* data. This can be a
+ * stream that plays to a Sink or when the stream is used to implement
+ * a Source.
+ *
+ * \subsection ssec_stream_target Stream target
+ *
+ * To make the newly connected stream automatically connect to an existing
+ * PipeWire node, use the \ref PW_STREAM_FLAG_AUTOCONNECT and the port_path
+ * argument while connecting.
+ *
+ * \subsection ssec_stream_formats Stream formats
+ *
+ * An array of possible formats that this stream can consume or provide
+ * must be specified.
+ *
+ * \section sec_format Format negotiation
+ *
+ * After connecting the stream, the server will want to configure some
+ * parameters on the stream. You will be notified of these changes
+ * with the param_changed event.
+ *
+ * When a format param change is emitted, the client should now prepare
+ * itself to deal with the format and complete the negotiation procedure
+ * with a call to \ref pw_stream_update_params().
+ *
+ * As arguments to \ref pw_stream_update_params() an array of spa_param
+ * structures must be given. They contain parameters such as buffer size,
+ * number of buffers, required metadata and other parameters for the
+ * media buffers.
+ *
+ * \section sec_buffers Buffer negotiation
+ *
+ * After completing the format negotiation, PipeWire will allocate and
+ * notify the stream of the buffers that will be used to exchange data
+ * between client and server.
+ *
+ * With the add_buffer event, a stream will be notified of a new buffer
+ * that can be used for data transport. You can attach user_data to these
+ * buffers. The buffers can only be used with the stream that emitted
+ * the add_buffer event.
+ *
+ * After the buffers are negotiated, the stream will transition to the
+ * \ref PW_STREAM_STATE_PAUSED state.
+ *
+ * \section sec_streaming Streaming
+ *
+ * From the \ref PW_STREAM_STATE_PAUSED state, the stream can be set to
+ * the \ref PW_STREAM_STATE_STREAMING state by the PipeWire server when
+ * data transport is started.
+ *
+ * Depending on how the stream was connected it will need to Produce or
+ * Consume data for/from PipeWire as explained in the following
+ * subsections.
+ *
+ * \subsection ssec_consume Consume data
+ *
+ * The process event is emitted for each new buffer that can be
+ * consumed.
+ *
+ * \ref pw_stream_dequeue_buffer() should be used to get the data and
+ * metadata of the buffer.
+ *
+ * The buffer is owned by the stream and stays alive until the
+ * remove_buffer event is emitted or the stream is destroyed.
+ *
+ * When the buffer has been processed, call \ref pw_stream_queue_buffer()
+ * to let PipeWire reuse the buffer.
+ *
+ * \subsection ssec_produce Produce data
+ *
+ * \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled.
+ *
+ * The buffer is owned by the stream and stays alive until the
+ * remove_buffer event is emitted or the stream is destroyed.
+ *
+ * Filled buffers should be queued with \ref pw_stream_queue_buffer().
+ *
+ * The process event is emitted when PipeWire has emptied a buffer that
+ * can now be refilled.
+ *
+ * \section sec_stream_disconnect Disconnect
+ *
+ * Use \ref pw_stream_disconnect() to disconnect a stream after use.
+ *
+ * \section sec_stream_configuration Configuration
+ *
+ * \subsection ssec_config_properties Stream Properties
+ *
+ * \subsection ssec_config_rules Stream Rules
+ *
+ * \section sec_stream_environment Environment Variables
+ *
+ */
+/** \defgroup pw_stream Stream
+ *
+ * \brief PipeWire stream objects
+ *
+ * The stream object provides a convenient way to send and
+ * receive data streams from/to PipeWire.
+ *
+ * See also \ref page_streams and \ref api_pw_core
+ */
+
+/**
+ * \addtogroup pw_stream
+ * \{
+ */
+struct pw_stream;
+
+#include <spa/buffer/buffer.h>
+#include <spa/param/param.h>
+#include <spa/pod/command.h>
+
+/** \enum pw_stream_state The state of a stream */
+enum pw_stream_state {
+ PW_STREAM_STATE_ERROR = -1, /**< the stream is in error */
+ PW_STREAM_STATE_UNCONNECTED = 0, /**< unconnected */
+ PW_STREAM_STATE_CONNECTING = 1, /**< connection is in progress */
+ PW_STREAM_STATE_PAUSED = 2, /**< paused */
+ PW_STREAM_STATE_STREAMING = 3 /**< streaming */
+};
+
+/** a buffer structure obtained from pw_stream_dequeue_buffer(). The size of this
+ * structure can grow as more field are added in the future */
+struct pw_buffer {
+ struct spa_buffer *buffer; /**< the spa buffer */
+ void *user_data; /**< user data attached to the buffer */
+ uint64_t size; /**< This field is set by the user and the sum of
+ * all queued buffer is returned in the time info.
+ * For audio, it is advised to use the number of
+ * samples in the buffer for this field. */
+ uint64_t requested; /**< For playback streams, this field contains the
+ * suggested amount of data to provide. For audio
+ * streams this will be the amount of samples
+ * required by the resampler. This field is 0
+ * when no suggestion is provided. Since 0.3.49 */
+};
+
+struct pw_stream_control {
+ const char *name; /**< name of the control */
+ uint32_t flags; /**< extra flags (unused) */
+ float def; /**< default value */
+ float min; /**< min value */
+ float max; /**< max value */
+ float *values; /**< array of values */
+ uint32_t n_values; /**< number of values in array */
+ uint32_t max_values; /**< max values that can be set on this control */
+};
+
+/** A time structure.
+ *
+ * Use pw_stream_get_time_n() to get an updated time snapshot of the stream.
+ * The time snapshot can give information about the time in the driver of the
+ * graph, the delay to the edge of the graph and the internal queuing in the
+ * stream.
+ *
+ * pw_time.ticks gives a monotonic increasing counter of the time in the graph
+ * driver. I can be used to generate a timetime to schedule samples as well
+ * as detect discontinuities in the timeline caused by xruns.
+ *
+ * pw_time.delay is expressed as pw_time.rate, the time domain of the graph. This
+ * value, and pw_time.ticks, were captured at pw_time.now and can be extrapolated
+ * to the current time like this:
+ *
+ * struct timespec ts;
+ * clock_gettime(CLOCK_MONOTONIC, &ts);
+ * int64_t diff = SPA_TIMESPEC_TO_NSEC(&ts) - pw_time.now;
+ * int64_t elapsed = (pw_time.rate.denom * diff) / (pw_time.rate.num * SPA_NSEC_PER_SEC);
+ *
+ * pw_time.delay contains the total delay that a signal will travel through the
+ * graph. This includes the delay caused by filters in the graph as well as delays
+ * caused by the hardware. The delay is usually quite stable and should only change when
+ * the topology, quantum or samplerate of the graph changes.
+ *
+ * pw_time.queued and pw_time.buffered is expressed in the time domain of the stream,
+ * or the format that is used for the buffers of this stream.
+ *
+ * pw_time.queued is the sum of all the pw_buffer.size fields of the buffers that are
+ * currently queued in the stream but not yet processed. The application can choose
+ * the units of this value, for example, time, samples or bytes (below expressed
+ * as app.rate).
+ *
+ * pw_time.buffered is format dependent, for audio/raw it contains the number of samples
+ * that are buffered inside the resampler/converter.
+ *
+ * The total delay of data in a stream is the sum of the queued and buffered data
+ * (not yet processed data) and the delay to the edge of the graph, usually a
+ * playback or capture device.
+ *
+ * For an audio playback stream, if you were to queue a buffer, the total delay
+ * in milliseconds for the first sample in the newly queued buffer to be played
+ * by the hardware can be calculated as:
+ *
+ * (pw_time.buffered * 1000 / stream.samplerate) +
+ * (pw_time.queued * 1000 / app.rate) +
+ * ((pw_time.delay - elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom)
+ *
+ * The current extrapolated time (in ms) in the source or sink can be calculated as:
+ *
+ * (pw_time.ticks + elapsed) * 1000 * pw_time.rate.num / pw_time.rate.denom
+ *
+ *
+ * stream time domain graph time domain
+ * /-----------------------\/-----------------------------\
+ *
+ * queue +-+ +-+ +-----------+ +--------+
+ * ----> | | | |->| converter | -> graph -> | kernel | -> speaker
+ * <---- +-+ +-+ +-----------+ +--------+
+ * dequeue buffers \-------------------/\--------/
+ * graph internal
+ * latency latency
+ * \--------/\-------------/\-----------------------------/
+ * queued buffered delay
+ */
+struct pw_time {
+ int64_t now; /**< the monotonic time in nanoseconds. This is the time
+ * when this time report was updated. It is usually
+ * updated every graph cycle. You can use the current
+ * monotonic time to calculate the elapsed time between
+ * this report and the current state and calculate
+ * updated ticks and delay values. */
+ struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually
+ * expressed in 1/<samplerate>. */
+ uint64_t ticks; /**< the ticks at \a now. This is the current time that
+ * the remote end is reading/writing. This is monotonicaly
+ * increasing. */
+ int64_t delay; /**< delay to device. This is the time it will take for
+ * the next output sample of the stream to be presented by
+ * the playback device or the time a sample traveled
+ * from the capture device. This delay includes the
+ * delay introduced by all filters on the path between
+ * the stream and the device. The delay is normally
+ * constant in a graph and can change when the topology
+ * of the graph or the quantum changes. This delay does
+ * not include the delay caused by queued buffers. */
+ uint64_t queued; /**< data queued in the stream, this is the sum
+ * of the size fields in the pw_buffer that are
+ * currently queued */
+ uint64_t buffered; /**< for audio/raw streams, this contains the extra
+ * number of samples buffered in the resampler.
+ * Since 0.3.50. */
+ uint32_t queued_buffers; /**< The number of buffers that are queued. Since 0.3.50 */
+ uint32_t avail_buffers; /**< The number of buffers that can be dequeued. Since 0.3.50 */
+};
+
+#include <pipewire/port.h>
+
+/** Events for a stream. These events are always called from the mainloop
+ * unless explicitly documented otherwise. */
+struct pw_stream_events {
+#define PW_VERSION_STREAM_EVENTS 2
+ uint32_t version;
+
+ void (*destroy) (void *data);
+ /** when the stream state changes */
+ void (*state_changed) (void *data, enum pw_stream_state old,
+ enum pw_stream_state state, const char *error);
+
+ /** Notify information about a control. */
+ void (*control_info) (void *data, uint32_t id, const struct pw_stream_control *control);
+
+ /** when io changed on the stream. */
+ void (*io_changed) (void *data, uint32_t id, void *area, uint32_t size);
+ /** when a parameter changed */
+ void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
+
+ /** when a new buffer was created for this stream */
+ void (*add_buffer) (void *data, struct pw_buffer *buffer);
+ /** when a buffer was destroyed for this stream */
+ void (*remove_buffer) (void *data, struct pw_buffer *buffer);
+
+ /** when a buffer can be queued (for playback streams) or
+ * dequeued (for capture streams). This is normally called from the
+ * mainloop but can also be called directly from the realtime data
+ * thread if the user is prepared to deal with this. */
+ void (*process) (void *data);
+
+ /** The stream is drained */
+ void (*drained) (void *data);
+
+ /** A command notify, Since 0.3.39:1 */
+ void (*command) (void *data, const struct spa_command *command);
+
+ /** a trigger_process completed. Since version 0.3.40:2 */
+ void (*trigger_done) (void *data);
+};
+
+/** Convert a stream state to a readable string */
+const char * pw_stream_state_as_string(enum pw_stream_state state);
+
+/** \enum pw_stream_flags Extra flags that can be used in \ref pw_stream_connect() */
+enum pw_stream_flags {
+ PW_STREAM_FLAG_NONE = 0, /**< no flags */
+ PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect
+ * this stream */
+ PW_STREAM_FLAG_INACTIVE = (1 << 1), /**< start the stream inactive,
+ * pw_stream_set_active() needs to be
+ * called explicitly */
+ PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers except DmaBuf */
+ PW_STREAM_FLAG_DRIVER = (1 << 3), /**< be a driver */
+ PW_STREAM_FLAG_RT_PROCESS = (1 << 4), /**< call process from the realtime
+ * thread. You MUST use RT safe functions
+ * in the process callback. */
+ PW_STREAM_FLAG_NO_CONVERT = (1 << 5), /**< don't convert format */
+ PW_STREAM_FLAG_EXCLUSIVE = (1 << 6), /**< require exclusive access to the
+ * device */
+ PW_STREAM_FLAG_DONT_RECONNECT = (1 << 7), /**< don't try to reconnect this stream
+ * when the sink/source is removed */
+ PW_STREAM_FLAG_ALLOC_BUFFERS = (1 << 8), /**< the application will allocate buffer
+ * memory. In the add_buffer event, the
+ * data of the buffer should be set */
+ PW_STREAM_FLAG_TRIGGER = (1 << 9), /**< the output stream will not be scheduled
+ * automatically but _trigger_process()
+ * needs to be called. This can be used
+ * when the output of the stream depends
+ * on input from other streams. */
+};
+
+/** Create a new unconneced \ref pw_stream
+ * \return a newly allocated \ref pw_stream */
+struct pw_stream *
+pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
+ const char *name, /**< a stream media name */
+ struct pw_properties *props /**< stream properties, ownership is taken */);
+
+struct pw_stream *
+pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
+ const char *name, /**< a stream media name */
+ struct pw_properties *props,/**< stream properties, ownership is taken */
+ const struct pw_stream_events *events, /**< stream events */
+ void *data /**< data passed to events */);
+
+/** Destroy a stream */
+void pw_stream_destroy(struct pw_stream *stream);
+
+void pw_stream_add_listener(struct pw_stream *stream,
+ struct spa_hook *listener,
+ const struct pw_stream_events *events,
+ void *data);
+
+enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error);
+
+const char *pw_stream_get_name(struct pw_stream *stream);
+
+struct pw_core *pw_stream_get_core(struct pw_stream *stream);
+
+const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream);
+
+int pw_stream_update_properties(struct pw_stream *stream, const struct spa_dict *dict);
+
+/** Connect a stream for input or output on \a port_path.
+ * \return 0 on success < 0 on error.
+ *
+ * You should connect to the process event and use pw_stream_dequeue_buffer()
+ * to get the latest metadata and data. */
+int
+pw_stream_connect(struct pw_stream *stream, /**< a \ref pw_stream */
+ enum pw_direction direction, /**< the stream direction */
+ uint32_t target_id, /**< the target object id to connect to or
+ * PW_ID_ANY to let the manager
+ * select a target. */
+ enum pw_stream_flags flags, /**< stream flags */
+ const struct spa_pod **params, /**< an array with params. The params
+ * should ideally contain supported
+ * formats. */
+ uint32_t n_params /**< number of items in \a params */);
+
+/** Get the node ID of the stream.
+ * \return node ID. */
+uint32_t
+pw_stream_get_node_id(struct pw_stream *stream);
+
+/** Disconnect \a stream */
+int pw_stream_disconnect(struct pw_stream *stream);
+
+/** Set the stream in error state */
+int pw_stream_set_error(struct pw_stream *stream, /**< a \ref pw_stream */
+ int res, /**< a result code */
+ const char *error, /**< an error message */
+ ...) SPA_PRINTF_FUNC(3, 4);
+
+/** Complete the negotiation process with result code \a res
+ *
+ * This function should be called after notification of the format.
+
+ * When \a res indicates success, \a params contain the parameters for the
+ * allocation state. */
+int
+pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
+ const struct spa_pod **params, /**< an array of params. The params should
+ * ideally contain parameters for doing
+ * buffer allocation. */
+ uint32_t n_params /**< number of elements in \a params */);
+
+/** Get control values */
+const struct pw_stream_control *pw_stream_get_control(struct pw_stream *stream, uint32_t id);
+
+/** Set control values */
+int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...);
+
+/** Query the time on the stream */
+int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size);
+
+/** Query the time on the stream, deprecated since 0.3.50,
+ * use pw_stream_get_time_n() to get the fields added since 0.3.50. */
+SPA_DEPRECATED
+int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);
+
+/** Get a buffer that can be filled for playback streams or consumed
+ * for capture streams. */
+struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream);
+
+/** Submit a buffer for playback or recycle a buffer for capture. */
+int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
+
+/** Activate or deactivate the stream */
+int pw_stream_set_active(struct pw_stream *stream, bool active);
+
+/** Flush a stream. When \a drain is true, the drained callback will
+ * be called when all data is played or recorded */
+int pw_stream_flush(struct pw_stream *stream, bool drain);
+
+/** Check if the stream is driving. The stream needs to have the
+ * PW_STREAM_FLAG_DRIVER set. When the stream is driving,
+ * pw_stream_trigger_process() needs to be called when data is
+ * available (output) or needed (input). Since 0.3.34 */
+bool pw_stream_is_driving(struct pw_stream *stream);
+
+/** Trigger a push/pull on the stream. One iteration of the graph will
+ * scheduled and process() will be called. Since 0.3.34 */
+int pw_stream_trigger_process(struct pw_stream *stream);
+
+/**
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPEWIRE_STREAM_H */