mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	loop: add some more docs about loop_control
Add a gmainloop integration example. See #4467
This commit is contained in:
		
							parent
							
								
									78649b12f6
								
							
						
					
					
						commit
						b97dd00f26
					
				
					 3 changed files with 141 additions and 8 deletions
				
			
		| 
						 | 
					@ -189,6 +189,26 @@ SPA_API_LOOP void spa_loop_control_hook_after(struct spa_hook_list *l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Control an event loop
 | 
					 * Control an event loop
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The event loop control function provide API to run the event loop.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The below (pseudo)code is a minimal example outlining the use of the loop
 | 
				
			||||||
 | 
					 * control:
 | 
				
			||||||
 | 
					 * \code{.c}
 | 
				
			||||||
 | 
					 * spa_loop_control_enter(loop);
 | 
				
			||||||
 | 
					 * while (running) {
 | 
				
			||||||
 | 
					 *   spa_loop_control_iterate(loop, -1);
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * spa_loop_control_leave(loop);
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It is also possible to add the loop to an existing event loop by using the
 | 
				
			||||||
 | 
					 * spa_loop_control_get_fd() call. This fd will become readable when activity
 | 
				
			||||||
 | 
					 * has been detected on the sources in the loop. spa_loop_control_iterate() with
 | 
				
			||||||
 | 
					 * a 0 timeout should be called to process the pending sources.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * spa_loop_control_enter() and spa_loop_control_leave() should be called once
 | 
				
			||||||
 | 
					 * from the thread that will run the iterate() function.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct spa_loop_control_methods {
 | 
					struct spa_loop_control_methods {
 | 
				
			||||||
	/* the version of this structure. This can be used to expand this
 | 
						/* the version of this structure. This can be used to expand this
 | 
				
			||||||
| 
						 | 
					@ -196,10 +216,19 @@ struct spa_loop_control_methods {
 | 
				
			||||||
#define SPA_VERSION_LOOP_CONTROL_METHODS	1
 | 
					#define SPA_VERSION_LOOP_CONTROL_METHODS	1
 | 
				
			||||||
	uint32_t version;
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** get the loop fd
 | 
				
			||||||
 | 
						 * \param object the control to query
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Get the fd of this loop control. This fd will be readable when a
 | 
				
			||||||
 | 
						 * source in the loop has activity. The user should call iterate()
 | 
				
			||||||
 | 
						 * with a 0 timeout to schedule one iteration of the loop and dispatch
 | 
				
			||||||
 | 
						 * the sources.
 | 
				
			||||||
 | 
						 * \return the fd of the loop
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	int (*get_fd) (void *object);
 | 
						int (*get_fd) (void *object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Add a hook
 | 
						/** Add a hook
 | 
				
			||||||
	 * \param ctrl the control to change
 | 
						 * \param object the control to change
 | 
				
			||||||
	 * \param hooks the hooks to add
 | 
						 * \param hooks the hooks to add
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Adds hooks to the loop controlled by \a ctrl.
 | 
						 * Adds hooks to the loop controlled by \a ctrl.
 | 
				
			||||||
| 
						 | 
					@ -210,18 +239,19 @@ struct spa_loop_control_methods {
 | 
				
			||||||
			  void *data);
 | 
								  void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Enter a loop
 | 
						/** Enter a loop
 | 
				
			||||||
	 * \param ctrl the control
 | 
						 * \param object the control
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Start an iteration of the loop. This function should be called
 | 
						 * This function should be called before calling iterate and is
 | 
				
			||||||
	 * before calling iterate and is typically used to capture the thread
 | 
						 * typically used to capture the thread that this loop will run in.
 | 
				
			||||||
	 * that this loop will run in.
 | 
						 * It should ideally be called once from the thread that will run
 | 
				
			||||||
 | 
						 * the loop.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	void (*enter) (void *object);
 | 
						void (*enter) (void *object);
 | 
				
			||||||
	/** Leave a loop
 | 
						/** Leave a loop
 | 
				
			||||||
	 * \param ctrl the control
 | 
						 * \param object the control
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Ends the iteration of a loop. This should be called after calling
 | 
						 * It should ideally be called once after calling iterate when the loop
 | 
				
			||||||
	 * iterate.
 | 
						 * will no longer be iterated from the thread that called enter().
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	void (*leave) (void *object);
 | 
						void (*leave) (void *object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/examples/gmain.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/examples/gmain.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <glib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pipewire/pipewire.h>
 | 
				
			||||||
 | 
					#include <spa/utils/result.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _PipeWireSource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GSource base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct pw_loop *loop;
 | 
				
			||||||
 | 
					} PipeWireSource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean
 | 
				
			||||||
 | 
					pipewire_loop_source_dispatch (GSource     *source,
 | 
				
			||||||
 | 
					                               GSourceFunc  callback,
 | 
				
			||||||
 | 
					                               gpointer     user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						PipeWireSource *s = (PipeWireSource *) source;
 | 
				
			||||||
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = pw_loop_iterate (s->loop, 0);
 | 
				
			||||||
 | 
						if (result < 0)
 | 
				
			||||||
 | 
							g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GSourceFuncs pipewire_source_funcs =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						.dispatch = pipewire_loop_source_dispatch,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void registry_event_global(void *data, uint32_t id,
 | 
				
			||||||
 | 
							uint32_t permissions, const char *type, uint32_t version,
 | 
				
			||||||
 | 
							const struct spa_dict *props)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("object: id:%u type:%s/%d\n", id, type, version);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_registry_events registry_events = {
 | 
				
			||||||
 | 
						PW_VERSION_REGISTRY_EVENTS,
 | 
				
			||||||
 | 
						.global = registry_event_global,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GMainLoop *main_loop;
 | 
				
			||||||
 | 
						PipeWireSource *source;
 | 
				
			||||||
 | 
						struct pw_loop *loop;
 | 
				
			||||||
 | 
						struct pw_context *context;
 | 
				
			||||||
 | 
						struct pw_core *core;
 | 
				
			||||||
 | 
						struct pw_registry *registry;
 | 
				
			||||||
 | 
						struct spa_hook registry_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						main_loop = g_main_loop_new (NULL, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_init(&argc, &argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						loop = pw_loop_new(NULL /* properties */);
 | 
				
			||||||
 | 
						/* wrap */
 | 
				
			||||||
 | 
						source = (PipeWireSource *) g_source_new (&pipewire_source_funcs,
 | 
				
			||||||
 | 
					                                        sizeof (PipeWireSource));
 | 
				
			||||||
 | 
						source->loop = loop;
 | 
				
			||||||
 | 
						g_source_add_unix_fd (&source->base,
 | 
				
			||||||
 | 
					                        pw_loop_get_fd (loop),
 | 
				
			||||||
 | 
					                        G_IO_IN | G_IO_ERR);
 | 
				
			||||||
 | 
						g_source_attach (&source->base, NULL);
 | 
				
			||||||
 | 
						g_source_unref (&source->base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						context = pw_context_new(loop,
 | 
				
			||||||
 | 
								NULL /* properties */,
 | 
				
			||||||
 | 
								0 /* user_data size */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core = pw_context_connect(context,
 | 
				
			||||||
 | 
								NULL /* properties */,
 | 
				
			||||||
 | 
								0 /* user_data size */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						registry = pw_core_get_registry(core, PW_VERSION_REGISTRY,
 | 
				
			||||||
 | 
								0 /* user_data size */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_zero(registry_listener);
 | 
				
			||||||
 | 
						pw_registry_add_listener(registry, ®istry_listener,
 | 
				
			||||||
 | 
									       ®istry_events, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* enter and leave must be called from the same thread that runs
 | 
				
			||||||
 | 
						 * the mainloop */
 | 
				
			||||||
 | 
						pw_loop_enter(loop);
 | 
				
			||||||
 | 
						g_main_loop_run(main_loop);
 | 
				
			||||||
 | 
						pw_loop_leave(loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_proxy_destroy((struct pw_proxy*)registry);
 | 
				
			||||||
 | 
						pw_core_disconnect(core);
 | 
				
			||||||
 | 
						pw_context_destroy(context);
 | 
				
			||||||
 | 
						pw_loop_destroy(loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_main_loop_unref(main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* [code] */
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ examples = [
 | 
				
			||||||
  'export-spa-device',
 | 
					  'export-spa-device',
 | 
				
			||||||
  'bluez-session',
 | 
					  'bluez-session',
 | 
				
			||||||
  'local-v4l2',
 | 
					  'local-v4l2',
 | 
				
			||||||
 | 
					  'gmain',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if not get_option('examples').allowed()
 | 
					if not get_option('examples').allowed()
 | 
				
			||||||
| 
						 | 
					@ -39,6 +40,7 @@ examples_extra_deps = {
 | 
				
			||||||
  'video-dsp-play': [sdl_dep],
 | 
					  'video-dsp-play': [sdl_dep],
 | 
				
			||||||
  'local-v4l2': [sdl_dep],
 | 
					  'local-v4l2': [sdl_dep],
 | 
				
			||||||
  'export-sink': [sdl_dep],
 | 
					  'export-sink': [sdl_dep],
 | 
				
			||||||
 | 
					  'gmain': [glib2_dep],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
foreach c : examples
 | 
					foreach c : examples
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue