From 6a3b5b1bf7beb66cd1c88856ff624b878d3a074c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 Jun 2017 19:25:01 +0200 Subject: [PATCH] documentation thread_main_loop -> thread_loop --- pipewire/client/context.h | 72 ++++++++- pipewire/client/interfaces.h | 34 ++++- pipewire/client/meson.build | 4 +- pipewire/client/pipewire.h | 50 ++++++- pipewire/client/stream.h | 134 ++++++++++++++++- pipewire/client/subscribe.h | 3 +- .../{thread-mainloop.c => thread-loop.c} | 138 +++++++++--------- pipewire/client/thread-loop.h | 133 +++++++++++++++++ pipewire/client/thread-mainloop.h | 82 ----------- pipewire/gst/gstpipewiredeviceprovider.c | 18 +-- pipewire/gst/gstpipewiredeviceprovider.h | 2 +- pipewire/gst/gstpipewiresink.c | 56 +++---- pipewire/gst/gstpipewiresink.h | 2 +- pipewire/gst/gstpipewiresrc.c | 80 +++++----- pipewire/gst/gstpipewiresrc.h | 2 +- pipewire/server/client-node.c | 8 +- pipewire/server/command.h | 2 +- pipewire/server/core.h | 9 ++ 18 files changed, 578 insertions(+), 251 deletions(-) rename pipewire/client/{thread-mainloop.c => thread-loop.c} (51%) create mode 100644 pipewire/client/thread-loop.h delete mode 100644 pipewire/client/thread-mainloop.h diff --git a/pipewire/client/context.h b/pipewire/client/context.h index 406824930..b6a17dd71 100644 --- a/pipewire/client/context.h +++ b/pipewire/client/context.h @@ -24,6 +24,72 @@ extern "C" { #endif +/** \page page_client_api Client API + * + * \section sec_client_api_overview Overview + * + * The client side API allows you to connect to the PipeWire server and + * perform actions on the PipeWire graph. This includes + * + * \li introspecting the objects on the server + * \li Creating nodes + * \li Linking nodes on their ports + * \li providing media to the server for playback or consumption + * \li retrieving media from the server + * + * \section sec_client_api_loop Event Loop Abstraction + * + * Most API is asynchronous and based around an event loop. Methods will + * start an operation which will cause a state change of the \ref pw_context + * object. Connect to the state_changed signal to be notified of these + * state changes. + * + * The most convenient way to deal with the asynchronous calls is probably + * with the thread loop (See \subpage page_thread_loop for more details). + * + * \section sec_client_api_context Context + * + * \subsection ssec_context_create Create + * + * To create a new context use pw_context_new(). You will + * need to pass a \ref pw_loop implementation to use as the event loop. + * + * A typical loop would be created with pw_thread_loop_new() but + * other implementation are possible. + * + * You will also need to pass properties for the context. Use + * pw_fill_context_properties() to get a default set of properties. + * + * After creating the context, you can track the state of the context + * by listening for the state_changed signal. + * + * \subsection ssec_client_api_context_connect Connecting + * + * A context must be connected to a server before any operation can be + * issued. Calling pw_context_connect() will initiate the connection + * procedure. + * + * When connecting, the context will automatically create a registry + * proxy to get notified of server objects. This behaviour can be disabled + * by passing the \ref PW_CONTEXT_FLAG_NO_REGISTRY. You can create your + * own registry later from the core_proxy member of the context. + * + * The context will automatically create proxies for all remote objects + * and will bind to them. Use the subscription signal to reveive + * notifications about objects. You can also disable this behaviour + * with the \ref PW_CONTEXT_FLAG_NO_PROXY flag and manually bind to + * the objects you are interested in. + * + * \subsection ssec_client_api_context_functions Streams + * + * Data exchange with the PipeWire server is done with the \ref pw_stream + * object. \subpage page_streams + * + * \subsection ssec_client_api_context_disconnect Disconnect + * + * Use pw_context_disconnect() to disconnect from the server. + */ + #include #include #include @@ -42,7 +108,7 @@ enum pw_context_state { /** Convert a \ref pw_context_state to a readable string \memberof pw_context */ const char *pw_context_state_as_string(enum pw_context_state state); -/** \enum pw_context_flags Extra flags passed to \ref pw_context_connect() \memberof pw_context */ +/** \enum pw_context_flags Extra flags passed to pw_context_connect() \memberof pw_context */ enum pw_context_flags { PW_CONTEXT_FLAG_NONE = 0, /**< no flags */ PW_CONTEXT_FLAG_NO_REGISTRY = (1 << 0), /**< don't create the registry object */ @@ -57,6 +123,8 @@ enum pw_context_flags { * a \ref pw_context is created and used to connect to the server. * A \ref pw_proxy for the core object will automatically be created * when connecting. + * + * See also \ref page_client_api */ struct pw_context { char *name; /**< the application name */ @@ -64,7 +132,7 @@ struct pw_context { struct pw_type type; /**< the type map */ - struct pw_loop *loop; /**< the main loop */ + struct pw_loop *loop; /**< the loop */ struct pw_proxy *core_proxy; /**< proxy for the core object */ struct pw_proxy *registry_proxy; /**< proxy for the registry object. Can diff --git a/pipewire/client/interfaces.h b/pipewire/client/interfaces.h index 39e09abce..85bbdb6b8 100644 --- a/pipewire/client/interfaces.h +++ b/pipewire/client/interfaces.h @@ -32,6 +32,22 @@ extern "C" { #include +/** + * \page page_pipewire The PipeWire protocol + * \section page_ifaces_pipewire Interfaces + * - \subpage page_iface_pw_core - core global object + * - \subpage page_iface_pw_registry - global registry object + */ + +/** + * \page page_iface_pw_core pw_core + * \section page_iface_pw_core_desc Description + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + * \section page_iface_pw_core API + */ + #define PW_CORE_METHOD_CLIENT_UPDATE 0 #define PW_CORE_METHOD_SYNC 1 #define PW_CORE_METHOD_GET_REGISTRY 2 @@ -40,15 +56,14 @@ extern "C" { #define PW_CORE_METHOD_UPDATE_TYPES 5 #define PW_CORE_METHOD_NUM 6 -/** \file +/** + * \struct pw_core_methods + * \brief Core methods * - * The object interfaces - * - * Methods are sent from client to server and events from - * server to client. + * The core global object. This is a singleton object used for + * creating new objects in the PipeWire server. It is also used + * for internal features. */ - -/** Core methods */ struct pw_core_methods { /** * Update the client properties @@ -127,7 +142,10 @@ struct pw_core_methods { #define PW_CORE_EVENT_UPDATE_TYPES 4 #define PW_CORE_EVENT_NUM 5 -/** Core events */ +/** \struct pw_core_events + * \brief Core events + * \ingroup pw_core_interface The pw_core interface + */ struct pw_core_events { /** * Notify new core info diff --git a/pipewire/client/meson.build b/pipewire/client/meson.build index 9cda8f8ae..a59b30cac 100644 --- a/pipewire/client/meson.build +++ b/pipewire/client/meson.build @@ -16,7 +16,7 @@ pipewire_headers = [ 'sig.h', 'stream.h', 'subscribe.h', - 'thread-mainloop.h', + 'thread-loop.h', 'transport.h', 'type.h', 'utils.h', @@ -36,7 +36,7 @@ pipewire_sources = [ 'stream.c', 'pipewire.c', 'rtkit.c', - 'thread-mainloop.c', + 'thread-loop.c', 'transport.c', 'type.c', 'utils.c', diff --git a/pipewire/client/pipewire.h b/pipewire/client/pipewire.h index 3607e25b7..4d7b61acc 100644 --- a/pipewire/client/pipewire.h +++ b/pipewire/client/pipewire.h @@ -29,7 +29,7 @@ extern "C" { #include #include #include -#include +#include #include #include #include @@ -37,6 +37,54 @@ extern "C" { #include +/** \mainpage + * + * \section sec_intro Introduction + * + * This document describes the API for the PipeWire multimedia server. + * The API consists of two parts: + * + * \li The client side API (See \subpage page_client_api) + * \li The server side API and tools to build new modules (See + * \subpage page_server_api) + * + * \section sec_errors Error reporting + * + * Functions return either NULL or a negative int error code when an + * error occurs. Error codes are used from the SPA plugin library on + * which PipeWire is built. + * + * Some functions might return asynchronously. The error code for such + * functions is positive and SPA_RESULT_IS_ASYNC() will return true. + * SPA_RESULT_ASYNC_SEQ() can be used to get the unique sequence number + * associated with the async operation. + * + * The object returning the async result code will have some way to + * signal the completion of the async operation (with, for example, a + * callback). The sequence number can be used to see which operation + * completed. + * + * \section sec_logging Logging + * + * The 'PIPEWIRE_DEBUG' environment variable can be used to enable + * more debugging. The format is: + * + * [:,...] + * + * - : specifies the log level: + * + `0`: no logging is enabled + * + `1`: Error logging is enabled + * + `2`: Warnings are enabled + * + `3`: Informational messages are enabled + * + `4`: Debug messages are enabled + * + `5`: Trace messages are enabled. These messages can be logged + * from the realtime threads. + * + * - : Specifies a string category to enable. Many categories + * can be separated by commas. Current categories are: + * + `connection`: to log connection messages + */ + /** \class pw_pipewire * * \brief PipeWire initalization and infrasctructure functions diff --git a/pipewire/client/stream.h b/pipewire/client/stream.h index c2e8a8120..817381741 100644 --- a/pipewire/client/stream.h +++ b/pipewire/client/stream.h @@ -29,6 +29,133 @@ extern "C" { #endif +/** \page page_streams Media Streams + * + * \section sec_overview Overview + * + * Media streams are used to exchange data with the PipeWire server. A + * stream is a wrapper around a \ref pw_client_node with one port. + * + * 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 manage the \ref pw_client_node proxy + * yourself. + * + * \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. You can use \ref + * pw_fill_stream_properties() to get a basic set of properties for the + * stream. + * + * Once the stream is created, the state_changed signal 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. + * + * \subsection ssec_stream_mode Stream modes + * + * The stream mode specifies how the data will be exchanged with PipeWire. + * The following stream modes are available + * + * \li \ref PW_STREAM_MODE_BUFFER: data is exchanged with fixed size + * buffers. This is ideal for video frames or equal sized audio + * frames. + * \li \ref PW_STREAM_MODE_RINGBUFFER: data is exhanged with a fixed + * size ringbuffer. This is ideal for variable sized audio packets + * or compressed media. + * + * \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, it will transition to the \ref + * PW_STREAM_STATE_CONFIGURE state. In this state the format will be + * negotiated by the PipeWire server. + * + * Once the format has been selected, the format_changed signal is + * emited with the configured format as a parameter. + * + * The client should now prepare itself to deal with the format and + * complete the negotiation procedure with a call to \ref + * pw_stream_finish_format(). + * + * As arguments to \ref pw_stream_finish_format() 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 signal, a stream will be notified of a new buffer + * that can be used for data transport. + * + * Afer 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 new_buffer signal is emited for each new buffer can can be + * consumed. + * + * \ref pw_stream_peek_buffer() should be used to get the data and metadata + * of the buffer. + * + * When the buffer is no longer in use, call \ref pw_stream_recycle_buffer() + * to let PipeWire reuse the buffer. + * + * \subsection ssec_produce Produce data + * + * The need_buffer signal is emited when PipeWire needs a new buffer for this + * stream. + * + * \ref pw_stream_get_empty_buffer() gives the id of an empty buffer. + * Use \ref pw_stream_peek_buffer() to get the data and metadata that should + * be filled. + * + * To send the filled buffer, use \ref pw_stream_send_buffer(). + * + * The new_buffer signal is emited when PipeWire no longer uses the buffer + * and it can be safely reused. + * + * \section sec_stream_disconnect Disconnect + * + * Use \ref pw_stream_disconnect() to disconnect a stream after use. + */ + /** \enum pw_stream_state The state of a stream \memberof pw_stream */ enum pw_stream_state { PW_STREAM_STATE_ERROR = -1, /**< the strean is in error */ @@ -47,7 +174,7 @@ 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() \memberof pw_stream */ enum pw_stream_flags { PW_STREAM_FLAG_NONE = 0, /**< no flags */ - PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< don't try to automatically connect + PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect * this stream */ PW_STREAM_FLAG_CLOCK_UPDATE = (1 << 1), /**< request periodic clock updates for * this stream */ @@ -72,6 +199,8 @@ struct pw_time { * * The stream object provides a convenient way to send and * receive data streams from/to PipeWire. + * + * See also \ref page_streams and \ref page_client_api */ struct pw_stream { struct pw_context *context; /**< the owner context */ @@ -109,7 +238,8 @@ struct pw_stream { struct pw_stream * pw_stream_new(struct pw_context *context, - const char *name, struct pw_properties *props); + const char *name, + struct pw_properties *props); void pw_stream_destroy(struct pw_stream *stream); diff --git a/pipewire/client/subscribe.h b/pipewire/client/subscribe.h index 948f20f12..20c571593 100644 --- a/pipewire/client/subscribe.h +++ b/pipewire/client/subscribe.h @@ -44,8 +44,7 @@ extern "C" { #define PIPEWIRE_TYPE__Module "PipeWire:Object:Module" #define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":" -/** \class pw_subscribe - * +/** \enum pw_subscription_event * subscription events */ enum pw_subscription_event { diff --git a/pipewire/client/thread-mainloop.c b/pipewire/client/thread-loop.c similarity index 51% rename from pipewire/client/thread-mainloop.c rename to pipewire/client/thread-loop.c index 017b90e89..646295a35 100644 --- a/pipewire/client/thread-mainloop.c +++ b/pipewire/client/thread-loop.c @@ -20,11 +20,11 @@ #include #include "pipewire.h" -#include "thread-mainloop.h" +#include "thread-loop.h" /** \cond */ -struct thread_main_loop { - struct pw_thread_main_loop this; +struct thread_loop { + struct pw_thread_loop this; char *name; @@ -44,48 +44,48 @@ struct thread_main_loop { static void pre_hook(struct spa_loop_control *ctrl, void *data) { - struct thread_main_loop *impl = data; + struct thread_loop *impl = data; pthread_mutex_unlock(&impl->lock); } static void post_hook(struct spa_loop_control *ctrl, void *data) { - struct thread_main_loop *impl = data; + struct thread_loop *impl = data; pthread_mutex_lock(&impl->lock); } static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, void *data) { - struct thread_main_loop *impl = data; + struct thread_loop *impl = data; impl->running = false; } -/** Create a new \ref pw_thread_main_loop +/** Create a new \ref pw_thread_loop * * \param loop the loop to wrap * \param name the name of the thread or NULL - * \return a newly allocated \ref pw_thread_main_loop + * \return a newly allocated \ref pw_thread_loop * - * Make a new \ref pw_thread_main_loop that will run a mainloop on \a loop in + * Make a new \ref pw_thread_loop that will run \a loop in * a thread with \a name. * - * After this function you should probably call pw_thread_main_loop_start() to + * After this function you should probably call pw_thread_loop_start() to * actually start the thread * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -struct pw_thread_main_loop *pw_thread_main_loop_new(struct pw_loop *loop, const char *name) +struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, const char *name) { - struct thread_main_loop *impl; - struct pw_thread_main_loop *this; + struct thread_loop *impl; + struct pw_thread_loop *this; pthread_mutexattr_t attr; - impl = calloc(1, sizeof(struct thread_main_loop)); + impl = calloc(1, sizeof(struct thread_loop)); if (impl == NULL) return NULL; this = &impl->this; - pw_log_debug("thread-mainloop %p: new", impl); + pw_log_debug("thread-loop %p: new", impl); this->loop = loop; this->name = name ? strdup(name) : NULL; @@ -105,14 +105,14 @@ struct pw_thread_main_loop *pw_thread_main_loop_new(struct pw_loop *loop, const return this; } -/** Destroy a threaded main loop \memberof pw_thread_main_loop */ -void pw_thread_main_loop_destroy(struct pw_thread_main_loop *loop) +/** Destroy a threaded loop \memberof pw_thread_loop */ +void pw_thread_loop_destroy(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); pw_signal_emit(&loop->destroy_signal, loop); - pw_thread_main_loop_stop(loop); + pw_thread_loop_stop(loop); if (loop->name) free(loop->name); @@ -125,19 +125,19 @@ void pw_thread_main_loop_destroy(struct pw_thread_main_loop *loop) static void *do_loop(void *user_data) { - struct thread_main_loop *impl = user_data; - struct pw_thread_main_loop *this = &impl->this; + struct thread_loop *impl = user_data; + struct pw_thread_loop *this = &impl->this; int res; pthread_mutex_lock(&impl->lock); - pw_log_debug("thread-mainloop %p: enter thread", this); + pw_log_debug("thread-loop %p: enter thread", this); pw_loop_enter(this->loop); while (impl->running) { if ((res = pw_loop_iterate(this->loop, -1)) < 0) - pw_log_warn("thread-mainloop %p: iterate error %d", this, res); + pw_log_warn("thread-loop %p: iterate error %d", this, res); } - pw_log_debug("thread-mainloop %p: leave thread", this); + pw_log_debug("thread-loop %p: leave thread", this); pw_loop_leave(this->loop); pthread_mutex_unlock(&impl->lock); @@ -146,21 +146,21 @@ static void *do_loop(void *user_data) /** Start the thread to handle \a loop * - * \param loop a \ref pw_thread_main_loop + * \param loop a \ref pw_thread_loop * \return \ref SPA_RESULT_OK on success * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -int pw_thread_main_loop_start(struct pw_thread_main_loop *loop) +int pw_thread_loop_start(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); if (!impl->running) { int err; impl->running = true; if ((err = pthread_create(&impl->thread, NULL, do_loop, impl)) != 0) { - pw_log_warn("thread-mainloop %p: can't create thread: %s", impl, + pw_log_warn("thread-loop %p: can't create thread: %s", impl, strerror(err)); impl->running = false; return SPA_RESULT_ERROR; @@ -169,65 +169,65 @@ int pw_thread_main_loop_start(struct pw_thread_main_loop *loop) return SPA_RESULT_OK; } -/** Quit the main loop and stop its thread +/** Quit the loop and stop its thread * - * \param loop a \ref pw_thread_main_loop + * \param loop a \ref pw_thread_loop * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_stop(struct pw_thread_main_loop *loop) +void pw_thread_loop_stop(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - pw_log_debug("thread-mainloop: %p stopping", impl); + pw_log_debug("thread-loop: %p stopping", impl); if (impl->running) { - pw_log_debug("thread-mainloop: %p signal", impl); + pw_log_debug("thread-loop: %p signal", impl); pw_loop_signal_event(loop->loop, impl->event); - pw_log_debug("thread-mainloop: %p join", impl); + pw_log_debug("thread-loop: %p join", impl); pthread_join(impl->thread, NULL); - pw_log_debug("thread-mainloop: %p joined", impl); + pw_log_debug("thread-loop: %p joined", impl); impl->running = false; } - pw_log_debug("thread-mainloop: %p stopped", impl); + pw_log_debug("thread-loop: %p stopped", impl); } /** Lock the mutex associated with \a loop * - * \param loop a \ref pw_thread_main_loop + * \param loop a \ref pw_thread_loop * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_lock(struct pw_thread_main_loop *loop) +void pw_thread_loop_lock(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); pthread_mutex_lock(&impl->lock); } /** Unlock the mutex associated with \a loop * - * \param loop a \ref pw_thread_main_loop + * \param loop a \ref pw_thread_loop * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_unlock(struct pw_thread_main_loop *loop) +void pw_thread_loop_unlock(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); pthread_mutex_unlock(&impl->lock); } -/** Signal the main thread +/** Signal the thread * - * \param loop a \ref pw_thread_main_loop to signal + * \param loop a \ref pw_thread_loop to signal * \param wait_for_accept if we need to wait for accept * - * Signal the main thread of \a loop. If \a wait_for_accept is true, - * this function waits until \ref pw_thread_main_loop_accept() is called. + * Signal the thread of \a loop. If \a wait_for_accept is true, + * this function waits until \ref pw_thread_loop_accept() is called. * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_signal(struct pw_thread_main_loop *loop, bool wait_for_accept) +void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); if (impl->n_waiting > 0) pthread_cond_broadcast(&impl->cond); @@ -240,15 +240,15 @@ void pw_thread_main_loop_signal(struct pw_thread_main_loop *loop, bool wait_for_ } } -/** Wait for the loop thread to call \ref pw_thread_main_loop_signal() +/** Wait for the loop thread to call \ref pw_thread_loop_signal() * - * \param loop a \ref pw_thread_main_loop to signal + * \param loop a \ref pw_thread_loop to signal * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_wait(struct pw_thread_main_loop *loop) +void pw_thread_loop_wait(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); impl->n_waiting++; @@ -256,15 +256,15 @@ void pw_thread_main_loop_wait(struct pw_thread_main_loop *loop) impl->n_waiting--; } -/** Signal the loop thread waiting for accept with \ref pw_thread_main_loop_signal() +/** Signal the loop thread waiting for accept with \ref pw_thread_loop_signal() * - * \param loop a \ref pw_thread_main_loop to signal + * \param loop a \ref pw_thread_loop to signal * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -void pw_thread_main_loop_accept(struct pw_thread_main_loop *loop) +void pw_thread_loop_accept(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); impl->n_waiting_for_accept--; pthread_cond_signal(&impl->accept_cond); @@ -272,13 +272,13 @@ void pw_thread_main_loop_accept(struct pw_thread_main_loop *loop) /** Check if we are inside the thread of the loop * - * \param loop a \ref pw_thread_main_loop to signal + * \param loop a \ref pw_thread_loop to signal * \return true when called inside the thread of \a loop. * - * \memberof pw_thread_main_loop + * \memberof pw_thread_loop */ -bool pw_thread_main_loop_in_thread(struct pw_thread_main_loop *loop) +bool pw_thread_loop_in_thread(struct pw_thread_loop *loop) { - struct thread_main_loop *impl = SPA_CONTAINER_OF(loop, struct thread_main_loop, this); + struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); return pthread_self() == impl->thread; } diff --git a/pipewire/client/thread-loop.h b/pipewire/client/thread-loop.h new file mode 100644 index 000000000..cdc5d5082 --- /dev/null +++ b/pipewire/client/thread-loop.h @@ -0,0 +1,133 @@ +/* PipeWire + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PIPEWIRE_THREAD_LOOP_H__ +#define __PIPEWIRE_THREAD_LOOP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \page page_thread_loop Threaded Loop + * + * \section sec_thread_loop_overview Overview + * + * The threaded loop implementation is a special wrapper around the + * regular \ref pw_loop implementation. + * + * The added feature in the threaded loop is that it spawns a new thread + * that runs the wrapped loop. This allows a synchronous application to use + * the asynchronous API without risking to stall the PipeWire library. + * + * \section sec_thread_loop_create Creation + * + * A \ref pw_thread_loop object is created using pw_thread_loop_new(). + * The \ref pw_loop to wrap must be given as an argument along with the name + * for the thread that will be spawned. + * + * After allocating the object, the thread must be started with + * pw_thread_loop_start() + * + * \section sec_thread_loop_destruction Destruction + * + * When the PipeWire connection has been terminated, the thread must be + * stopped and the resources freed. Stopping the thread is done using + * pw_thread_loop_stop(), which must be called without the lock (see + * below) held. When that function returns, the thread is stopped and the + * \ref pw_thread_loop object can be freed using pw_thread_loop_destroy(). + * + * \section sec_thread_loop_locking Locking + * + * Since the PipeWire API doesn't allow concurrent accesses to objects, + * a locking scheme must be used to guarantee safe usage. The threaded + * loop API provides such a scheme through the functions + * pw_thread_loop_lock() and pw_thread_loop_unlock(). + * + * The lock is recursive, so it's safe to use it multiple times from the same + * thread. Just make sure you call pw_thread_loop_unlock() the same + * number of times you called pw_thread_loop_lock(). + * + * The lock needs to be held whenever you call any PipeWire function that + * uses an object associated with this loop. Make sure you do not hold + * on to the lock more than necessary though, as the threaded loop stops + * while the lock is held. + * + * \section sec_thread_loop_signals Signals and Callbacks + * + * All signals and callbacks are called with the thread lock held. + * + */ +/** \class pw_thread_loop + * + * \brief PipeWire threaded loop object + * + * The threaded loop object runs a \ref pw_loop in a separate thread + * and ensures proper locking is done. + * + * All of the loop callbacks will be executed with the loop + * lock held. + * + * See also \ref page_thread_loop + */ +struct pw_thread_loop { + struct pw_loop *loop; /**< the \ref pw_loop that is wrapped */ + char *name; /**< the thread name */ + + /** Emited when the threaded loop is destroyed */ + PW_SIGNAL(destroy_signal, (struct pw_listener *listener, + struct pw_thread_loop *loop)); +}; + +struct pw_thread_loop * +pw_thread_loop_new(struct pw_loop *loop, const char *name); + +void +pw_thread_loop_destroy(struct pw_thread_loop *loop); + +int +pw_thread_loop_start(struct pw_thread_loop *loop); + +void +pw_thread_loop_stop(struct pw_thread_loop *loop); + +void +pw_thread_loop_lock(struct pw_thread_loop *loop); + +void +pw_thread_loop_unlock(struct pw_thread_loop *loop); + +void +pw_thread_loop_wait(struct pw_thread_loop *loop); + +void +pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept); + +void +pw_thread_loop_accept(struct pw_thread_loop *loop); + +bool +pw_thread_loop_in_thread(struct pw_thread_loop *loop); + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_THREAD_LOOP_H__ */ diff --git a/pipewire/client/thread-mainloop.h b/pipewire/client/thread-mainloop.h deleted file mode 100644 index d329593cb..000000000 --- a/pipewire/client/thread-mainloop.h +++ /dev/null @@ -1,82 +0,0 @@ -/* PipeWire - * Copyright (C) 2015 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __PIPEWIRE_THREAD_MAIN_LOOP_H__ -#define __PIPEWIRE_THREAD_MAIN_LOOP_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \class pw_thread_main_loop - * - * \brief PipeWire threaded main loop object - * - * The threaded main loop object runs a \ref pw_loop in a separate thread - * and ensures proper locking is done. - * - * All of the loop callbacks will be executed with the main loop - * lock held. - */ -struct pw_thread_main_loop { - struct pw_loop *loop; /**< the \ref pw_loop that is wrapped */ - char *name; /**< the thread name */ - - /** Emited when the mainloop is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, - struct pw_thread_main_loop *loop)); -}; - -struct pw_thread_main_loop * -pw_thread_main_loop_new(struct pw_loop *loop, const char *name); - -void -pw_thread_main_loop_destroy(struct pw_thread_main_loop *loop); - -int -pw_thread_main_loop_start(struct pw_thread_main_loop *loop); - -void -pw_thread_main_loop_stop(struct pw_thread_main_loop *loop); - -void -pw_thread_main_loop_lock(struct pw_thread_main_loop *loop); - -void -pw_thread_main_loop_unlock(struct pw_thread_main_loop *loop); - -void -pw_thread_main_loop_wait(struct pw_thread_main_loop *loop); - -void -pw_thread_main_loop_signal(struct pw_thread_main_loop *loop, bool wait_for_accept); - -void -pw_thread_main_loop_accept(struct pw_thread_main_loop *loop); - -bool -pw_thread_main_loop_in_thread(struct pw_thread_main_loop *loop); - -#ifdef __cplusplus -} -#endif - -#endif /* __PIPEWIRE_THREAD_MAIN_LOOP_H__ */ diff --git a/pipewire/gst/gstpipewiredeviceprovider.c b/pipewire/gst/gstpipewiredeviceprovider.c index cd05dc2e1..2f8f04807 100644 --- a/pipewire/gst/gstpipewiredeviceprovider.c +++ b/pipewire/gst/gstpipewiredeviceprovider.c @@ -443,7 +443,7 @@ on_context_state_changed (struct pw_listener *listener, GST_ERROR_OBJECT (self, "context error: %s", context->error); break; } - pw_thread_main_loop_signal (self->main_loop, FALSE); + pw_thread_loop_signal (self->main_loop, FALSE); } static gboolean @@ -455,17 +455,17 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) self->loop = pw_loop_new (); - if (!(self->main_loop = pw_thread_main_loop_new (self->loop, "pipewire-device-monitor"))) { + if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) { GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop"); goto failed_main_loop; } - if (pw_thread_main_loop_start (self->main_loop) != SPA_RESULT_OK) { + if (pw_thread_loop_start (self->main_loop) != SPA_RESULT_OK) { GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop"); goto failed_start; } - pw_thread_main_loop_lock (self->main_loop); + pw_thread_loop_lock (self->main_loop); if (!(self->context = pw_context_new (self->loop, self->client_name, NULL))) { GST_ERROR_OBJECT (self, "Failed to create context"); @@ -494,13 +494,13 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) break; /* Wait until something happens */ - pw_thread_main_loop_wait (self->main_loop); + pw_thread_loop_wait (self->main_loop); } GST_DEBUG_OBJECT (self, "connected"); pw_context_get_core_info (self->context, get_core_info_cb, self); - pw_thread_main_loop_unlock (self->main_loop); + pw_thread_loop_unlock (self->main_loop); return TRUE; @@ -508,9 +508,9 @@ not_running: pw_context_destroy (self->context); self->context = NULL; failed_context: - pw_thread_main_loop_unlock (self->main_loop); + pw_thread_loop_unlock (self->main_loop); failed_start: - pw_thread_main_loop_destroy (self->main_loop); + pw_thread_loop_destroy (self->main_loop); self->main_loop = NULL; failed_main_loop: pw_loop_destroy (self->loop); @@ -529,7 +529,7 @@ gst_pipewire_device_provider_stop (GstDeviceProvider * provider) self->context = NULL; } if (self->main_loop) { - pw_thread_main_loop_destroy (self->main_loop); + pw_thread_loop_destroy (self->main_loop); self->main_loop = NULL; } if (self->loop) { diff --git a/pipewire/gst/gstpipewiredeviceprovider.h b/pipewire/gst/gstpipewiredeviceprovider.h index 6fb54221e..8f288d13a 100644 --- a/pipewire/gst/gstpipewiredeviceprovider.h +++ b/pipewire/gst/gstpipewiredeviceprovider.h @@ -82,7 +82,7 @@ struct _GstPipeWireDeviceProvider { gchar *client_name; struct pw_loop *loop; - struct pw_thread_main_loop *main_loop; + struct pw_thread_loop *main_loop; struct pw_context *context; struct pw_listener ctx_state_changed; diff --git a/pipewire/gst/gstpipewiresink.c b/pipewire/gst/gstpipewiresink.c index c0e06dfa9..490019680 100644 --- a/pipewire/gst/gstpipewiresink.c +++ b/pipewire/gst/gstpipewiresink.c @@ -118,7 +118,7 @@ gst_pipewire_sink_finalize (GObject * object) g_object_unref (pwsink->pool); - pw_thread_main_loop_destroy (pwsink->main_loop); + pw_thread_loop_destroy (pwsink->main_loop); pwsink->main_loop = NULL; pw_loop_destroy (pwsink->loop); @@ -282,9 +282,9 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16)); port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - pw_thread_main_loop_lock (sink->main_loop); + pw_thread_loop_lock (sink->main_loop); pw_stream_finish_format (sink->stream, SPA_RESULT_OK, port_params, 2); - pw_thread_main_loop_unlock (sink->main_loop); + pw_thread_loop_unlock (sink->main_loop); } static void @@ -303,7 +303,7 @@ gst_pipewire_sink_init (GstPipeWireSink * sink) g_queue_init (&sink->queue); sink->loop = pw_loop_new (); - sink->main_loop = pw_thread_main_loop_new (sink->loop, "pipewire-sink-loop"); + sink->main_loop = pw_thread_loop_new (sink->loop, "pipewire-sink-loop"); GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop); } @@ -484,7 +484,7 @@ on_add_buffer (struct pw_listener *listener, gst_pipewire_pool_add_buffer (pwsink->pool, buf); g_hash_table_insert (pwsink->buf_ids, GINT_TO_POINTER (id), buf); - pw_thread_main_loop_signal (pwsink->main_loop, FALSE); + pw_thread_loop_signal (pwsink->main_loop, FALSE); } static void @@ -524,7 +524,7 @@ on_new_buffer (struct pw_listener *listener, if (buf) { gst_buffer_unref (buf); - pw_thread_main_loop_signal (pwsink->main_loop, FALSE); + pw_thread_loop_signal (pwsink->main_loop, FALSE); } } @@ -559,7 +559,7 @@ do_send_buffer (GstPipeWireSink *pwsink) if (!(res = pw_stream_send_buffer (pwsink->stream, data->id))) { g_warning ("can't send buffer"); - pw_thread_main_loop_signal (pwsink->main_loop, FALSE); + pw_thread_loop_signal (pwsink->main_loop, FALSE); } else pwsink->need_ready--; } @@ -599,7 +599,7 @@ on_state_changed (struct pw_listener *listener, ("stream error: %s", stream->error), (NULL)); break; } - pw_thread_main_loop_signal (pwsink->main_loop, FALSE); + pw_thread_loop_signal (pwsink->main_loop, FALSE); } static void @@ -625,7 +625,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) possible = gst_caps_to_format_all (caps); - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); state = pwsink->stream->state; if (state == PW_STREAM_STATE_ERROR) @@ -654,12 +654,12 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (state == PW_STREAM_STATE_ERROR) goto start_error; - pw_thread_main_loop_wait (pwsink->main_loop); + pw_thread_loop_wait (pwsink->main_loop); } } res = TRUE; - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); pwsink->negotiated = res; @@ -668,7 +668,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) start_error: { GST_ERROR ("could not start stream"); - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); g_ptr_array_unref (possible); return FALSE; } @@ -685,7 +685,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) if (!pwsink->negotiated) goto not_negotiated; - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); if (pwsink->stream->state != PW_STREAM_STATE_STREAMING) goto done; @@ -715,7 +715,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) do_send_buffer (pwsink); done: - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); return res; @@ -754,7 +754,7 @@ gst_pipewire_sink_start (GstBaseSink * basesink) props = NULL; } - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); pwsink->stream = pw_stream_new (pwsink->ctx, pwsink->client_name, props); pwsink->pool->stream = pwsink->stream; @@ -764,7 +764,7 @@ gst_pipewire_sink_start (GstBaseSink * basesink) pw_signal_add (&pwsink->stream->remove_buffer, &pwsink->stream_remove_buffer, on_remove_buffer); pw_signal_add (&pwsink->stream->new_buffer, &pwsink->stream_new_buffer, on_new_buffer); pw_signal_add (&pwsink->stream->need_buffer, &pwsink->stream_need_buffer, on_need_buffer); - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); return TRUE; } @@ -774,14 +774,14 @@ gst_pipewire_sink_stop (GstBaseSink * basesink) { GstPipeWireSink *pwsink = GST_PIPEWIRE_SINK (basesink); - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); if (pwsink->stream) { pw_stream_disconnect (pwsink->stream); pw_stream_destroy (pwsink->stream); pwsink->stream = NULL; pwsink->pool->stream = NULL; } - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); pwsink->negotiated = FALSE; @@ -808,16 +808,16 @@ on_ctx_state_changed (struct pw_listener *listener, ("context error: %s", ctx->error), (NULL)); break; } - pw_thread_main_loop_signal (pwsink->main_loop, FALSE); + pw_thread_loop_signal (pwsink->main_loop, FALSE); } static gboolean gst_pipewire_sink_open (GstPipeWireSink * pwsink) { - if (pw_thread_main_loop_start (pwsink->main_loop) != SPA_RESULT_OK) + if (pw_thread_loop_start (pwsink->main_loop) != SPA_RESULT_OK) goto mainloop_error; - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); pwsink->ctx = pw_context_new (pwsink->loop, g_get_application_name (), NULL); pw_signal_add (&pwsink->ctx->state_changed, &pwsink->ctx_state_changed, on_ctx_state_changed); @@ -833,9 +833,9 @@ gst_pipewire_sink_open (GstPipeWireSink * pwsink) if (state == PW_CONTEXT_STATE_ERROR) goto connect_error; - pw_thread_main_loop_wait (pwsink->main_loop); + pw_thread_loop_wait (pwsink->main_loop); } - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); return TRUE; @@ -848,7 +848,7 @@ mainloop_error: } connect_error: { - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); return FALSE; } } @@ -856,7 +856,7 @@ connect_error: static gboolean gst_pipewire_sink_close (GstPipeWireSink * pwsink) { - pw_thread_main_loop_lock (pwsink->main_loop); + pw_thread_loop_lock (pwsink->main_loop); if (pwsink->stream) { pw_stream_disconnect (pwsink->stream); } @@ -872,12 +872,12 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink) if (state == PW_CONTEXT_STATE_ERROR) break; - pw_thread_main_loop_wait (pwsink->main_loop); + pw_thread_loop_wait (pwsink->main_loop); } } - pw_thread_main_loop_unlock (pwsink->main_loop); + pw_thread_loop_unlock (pwsink->main_loop); - pw_thread_main_loop_stop (pwsink->main_loop); + pw_thread_loop_stop (pwsink->main_loop); if (pwsink->stream) { pw_stream_destroy (pwsink->stream); diff --git a/pipewire/gst/gstpipewiresink.h b/pipewire/gst/gstpipewiresink.h index 9f11fbc5f..936bfa287 100644 --- a/pipewire/gst/gstpipewiresink.h +++ b/pipewire/gst/gstpipewiresink.h @@ -78,7 +78,7 @@ struct _GstPipeWireSink { gboolean negotiated; struct pw_loop *loop; - struct pw_thread_main_loop *main_loop; + struct pw_thread_loop *main_loop; struct pw_context *ctx; struct pw_listener ctx_state_changed; diff --git a/pipewire/gst/gstpipewiresrc.c b/pipewire/gst/gstpipewiresrc.c index 030e4ba56..1e34a1902 100644 --- a/pipewire/gst/gstpipewiresrc.c +++ b/pipewire/gst/gstpipewiresrc.c @@ -196,7 +196,7 @@ gst_pipewire_src_finalize (GObject * object) clear_queue (pwsrc); - pw_thread_main_loop_destroy (pwsrc->main_loop); + pw_thread_loop_destroy (pwsrc->main_loop); pwsrc->main_loop = NULL; pw_loop_destroy (pwsrc->loop); pwsrc->loop = NULL; @@ -309,7 +309,7 @@ gst_pipewire_src_init (GstPipeWireSrc * src) src->buf_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_buffer_unref); src->loop = pw_loop_new (); - src->main_loop = pw_thread_main_loop_new (src->loop, "pipewire-main-loop"); + src->main_loop = pw_thread_loop_new (src->loop, "pipewire-main-loop"); GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop); } @@ -392,9 +392,9 @@ buffer_recycle (GstMiniObject *obj) src = data->src; GST_LOG_OBJECT (obj, "recycle buffer"); - pw_thread_main_loop_lock (src->main_loop); + pw_thread_loop_lock (src->main_loop); pw_stream_recycle_buffer (src->stream, data->id); - pw_thread_main_loop_unlock (src->main_loop); + pw_thread_loop_unlock (src->main_loop); return FALSE; } @@ -527,7 +527,7 @@ on_new_buffer (struct pw_listener *listener, g_queue_push_tail (&pwsrc->queue, buf); - pw_thread_main_loop_signal (pwsrc->main_loop, FALSE); + pw_thread_loop_signal (pwsrc->main_loop, FALSE); return; } @@ -553,7 +553,7 @@ on_state_changed (struct pw_listener *listener, ("stream error: %s", stream->error), (NULL)); break; } - pw_thread_main_loop_signal (pwsrc->main_loop, FALSE); + pw_thread_loop_signal (pwsrc->main_loop, FALSE); } static void @@ -581,7 +581,7 @@ parse_stream_properties (GstPipeWireSrc *pwsrc, struct pw_properties *props) static gboolean gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) { - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); GST_DEBUG_OBJECT (pwsrc, "doing stream start"); while (TRUE) { enum pw_stream_state state = pwsrc->stream->state; @@ -596,24 +596,24 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR) goto start_error; - pw_thread_main_loop_wait (pwsrc->main_loop); + pw_thread_loop_wait (pwsrc->main_loop); } parse_stream_properties (pwsrc, pwsrc->stream->properties); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); GST_DEBUG_OBJECT (pwsrc, "signal started"); pwsrc->started = TRUE; - pw_thread_main_loop_signal (pwsrc->main_loop, FALSE); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_signal (pwsrc->main_loop, FALSE); + pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; start_error: { GST_DEBUG_OBJECT (pwsrc, "error starting stream"); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return FALSE; } } @@ -623,7 +623,7 @@ wait_negotiated (GstPipeWireSrc *this) { enum pw_stream_state state; - pw_thread_main_loop_lock (this->main_loop); + pw_thread_loop_lock (this->main_loop); while (TRUE) { state = this->stream->state; @@ -639,10 +639,10 @@ wait_negotiated (GstPipeWireSrc *this) if (this->started) break; - pw_thread_main_loop_wait (this->main_loop); + pw_thread_loop_wait (this->main_loop); } GST_DEBUG_OBJECT (this, "got started signal"); - pw_thread_main_loop_unlock (this->main_loop); + pw_thread_loop_unlock (this->main_loop); return state; } @@ -687,7 +687,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) possible = gst_caps_to_format_all (caps); /* first disconnect */ - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); if (pwsrc->stream->state != PW_STREAM_STATE_UNCONNECTED) { GST_DEBUG_OBJECT (basesrc, "disconnect capture"); pw_stream_disconnect (pwsrc->stream); @@ -703,7 +703,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) goto connect_error; } - pw_thread_main_loop_wait (pwsrc->main_loop); + pw_thread_loop_wait (pwsrc->main_loop); } } @@ -730,9 +730,9 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR) goto connect_error; - pw_thread_main_loop_wait (pwsrc->main_loop); + pw_thread_loop_wait (pwsrc->main_loop); } - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); result = gst_pipewire_src_stream_start (pwsrc); @@ -767,7 +767,7 @@ no_common_caps: } connect_error: { - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return FALSE; } } @@ -831,11 +831,11 @@ gst_pipewire_src_unlock (GstBaseSrc * basesrc) { GstPipeWireSrc *pwsrc = GST_PIPEWIRE_SRC (basesrc); - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); GST_DEBUG_OBJECT (pwsrc, "setting flushing"); pwsrc->flushing = TRUE; - pw_thread_main_loop_signal (pwsrc->main_loop, FALSE); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_signal (pwsrc->main_loop, FALSE); + pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; } @@ -845,10 +845,10 @@ gst_pipewire_src_unlock_stop (GstBaseSrc * basesrc) { GstPipeWireSrc *pwsrc = GST_PIPEWIRE_SRC (basesrc); - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); GST_DEBUG_OBJECT (pwsrc, "unsetting flushing"); pwsrc->flushing = FALSE; - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; } @@ -934,7 +934,7 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (!pwsrc->negotiated) goto not_negotiated; - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); while (TRUE) { enum pw_stream_state state; @@ -953,9 +953,9 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (*buffer != NULL) break; - pw_thread_main_loop_wait (pwsrc->main_loop); + pw_thread_loop_wait (pwsrc->main_loop); } - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); if (pwsrc->is_live) base_time = GST_ELEMENT_CAST (psrc)->base_time; @@ -986,12 +986,12 @@ not_negotiated: } streaming_error: { - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return GST_FLOW_ERROR; } streaming_stopped: { - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return GST_FLOW_FLUSHING; } } @@ -1009,9 +1009,9 @@ gst_pipewire_src_stop (GstBaseSrc * basesrc) pwsrc = GST_PIPEWIRE_SRC (basesrc); - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); clear_queue (pwsrc); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; } @@ -1035,7 +1035,7 @@ on_ctx_state_changed (struct pw_listener *listener, ("context error: %s", ctx->error), (NULL)); break; } - pw_thread_main_loop_signal (pwsrc->main_loop, FALSE); + pw_thread_loop_signal (pwsrc->main_loop, FALSE); } static gboolean @@ -1057,10 +1057,10 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) { struct pw_properties *props; - if (pw_thread_main_loop_start (pwsrc->main_loop) != SPA_RESULT_OK) + if (pw_thread_loop_start (pwsrc->main_loop) != SPA_RESULT_OK) goto mainloop_failed; - pw_thread_main_loop_lock (pwsrc->main_loop); + pw_thread_loop_lock (pwsrc->main_loop); pwsrc->ctx = pw_context_new (pwsrc->loop, g_get_application_name (), NULL); pw_signal_add (&pwsrc->ctx->state_changed, &pwsrc->ctx_state_changed, on_ctx_state_changed); @@ -1077,7 +1077,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) if (state == PW_CONTEXT_STATE_ERROR) goto connect_error; - pw_thread_main_loop_wait (pwsrc->main_loop); + pw_thread_loop_wait (pwsrc->main_loop); } if (pwsrc->properties) { @@ -1096,7 +1096,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) pw_signal_add (&pwsrc->stream->new_buffer, &pwsrc->stream_new_buffer, on_new_buffer); pwsrc->clock = gst_pipewire_clock_new (pwsrc->stream); - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; @@ -1108,7 +1108,7 @@ mainloop_failed: } connect_error: { - pw_thread_main_loop_unlock (pwsrc->main_loop); + pw_thread_loop_unlock (pwsrc->main_loop); return FALSE; } } @@ -1118,7 +1118,7 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc) { clear_queue (pwsrc); - pw_thread_main_loop_stop (pwsrc->main_loop); + pw_thread_loop_stop (pwsrc->main_loop); g_hash_table_remove_all (pwsrc->buf_ids); diff --git a/pipewire/gst/gstpipewiresrc.h b/pipewire/gst/gstpipewiresrc.h index c3a15db28..dc2bf40fc 100644 --- a/pipewire/gst/gstpipewiresrc.h +++ b/pipewire/gst/gstpipewiresrc.h @@ -65,7 +65,7 @@ struct _GstPipeWireSrc { GstClockTime max_latency; struct pw_loop *loop; - struct pw_thread_main_loop *main_loop; + struct pw_thread_loop *main_loop; struct pw_context *ctx; struct pw_listener ctx_state_changed; diff --git a/pipewire/server/client-node.c b/pipewire/server/client-node.c index 45e50b64b..dbd702950 100644 --- a/pipewire/server/client-node.c +++ b/pipewire/server/client-node.c @@ -1178,9 +1178,13 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client, return NULL; } -void pw_client_node_destroy(struct pw_client_node *this) +/** Destroy a client node + * \param node the client node to destroy + * \memberof pw_client_node + */ +void pw_client_node_destroy(struct pw_client_node *node) { - pw_resource_destroy(this->resource); + pw_resource_destroy(node->resource); } /** Get the set of fds for this \ref pw_client_node diff --git a/pipewire/server/command.h b/pipewire/server/command.h index e440d3de5..e4c966497 100644 --- a/pipewire/server/command.h +++ b/pipewire/server/command.h @@ -27,7 +27,7 @@ extern "C" { #include -/** \class command +/** \class pw_command * * A configuration command */ diff --git a/pipewire/server/core.h b/pipewire/server/core.h index 379f68b86..a24b87c3d 100644 --- a/pipewire/server/core.h +++ b/pipewire/server/core.h @@ -36,6 +36,13 @@ struct pw_global; #include #include +/** \page page_server_api Server API + * + * \section page_server_overview Overview + * + * + */ + typedef int (*pw_bind_func_t) (struct pw_global *global, struct pw_client *client, uint32_t version, uint32_t id); @@ -67,6 +74,8 @@ struct pw_global { * * The server core object manages all resources available on the * server. + * + * See \ref page_server_api */ struct pw_core { struct pw_global *global; /**< the global of the core */