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
 | 
			
		||||
 *
 | 
			
		||||
 * 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 {
 | 
			
		||||
	/* 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
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/** Add a hook
 | 
			
		||||
	 * \param ctrl the control to change
 | 
			
		||||
	 * \param object the control to change
 | 
			
		||||
	 * \param hooks the hooks to add
 | 
			
		||||
	 *
 | 
			
		||||
	 * Adds hooks to the loop controlled by \a ctrl.
 | 
			
		||||
| 
						 | 
				
			
			@ -210,18 +239,19 @@ struct spa_loop_control_methods {
 | 
			
		|||
			  void *data);
 | 
			
		||||
 | 
			
		||||
	/** Enter a loop
 | 
			
		||||
	 * \param ctrl the control
 | 
			
		||||
	 * \param object the control
 | 
			
		||||
	 *
 | 
			
		||||
	 * Start an iteration of the loop. This function should be called
 | 
			
		||||
	 * before calling iterate and is typically used to capture the thread
 | 
			
		||||
	 * that this loop will run in.
 | 
			
		||||
	 * This function should be called before calling iterate and is
 | 
			
		||||
	 * typically used to capture the thread that this loop will run in.
 | 
			
		||||
	 * It should ideally be called once from the thread that will run
 | 
			
		||||
	 * the loop.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*enter) (void *object);
 | 
			
		||||
	/** Leave a loop
 | 
			
		||||
	 * \param ctrl the control
 | 
			
		||||
	 * \param object the control
 | 
			
		||||
	 *
 | 
			
		||||
	 * Ends the iteration of a loop. This should be called after calling
 | 
			
		||||
	 * iterate.
 | 
			
		||||
	 * It should ideally be called once after calling iterate when the loop
 | 
			
		||||
	 * will no longer be iterated from the thread that called enter().
 | 
			
		||||
	 */
 | 
			
		||||
	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',
 | 
			
		||||
  'bluez-session',
 | 
			
		||||
  'local-v4l2',
 | 
			
		||||
  'gmain',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if not get_option('examples').allowed()
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,7 @@ examples_extra_deps = {
 | 
			
		|||
  'video-dsp-play': [sdl_dep],
 | 
			
		||||
  'local-v4l2': [sdl_dep],
 | 
			
		||||
  'export-sink': [sdl_dep],
 | 
			
		||||
  'gmain': [glib2_dep],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
foreach c : examples
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue