### V4L2 SPA Example Setup Source: https://docs.pipewire.org/spa_2examples_2local-v4l2_8c-example.html Initializes PipeWire, loads the V4L2 SPA plugin, and sets up the necessary structures for video capture and rendering. Requires SDL2 for display. ```c #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static SPA_LOG_IMPL(default_log); #define MAX_BUFFERS 8 #define LOOP_TIMEOUT_MS 100 struct buffer { struct spa_buffer buffer; struct spa_meta metas[1]; struct spa_meta_header header; struct spa_data datas[1]; struct spa_chunk chunks[1]; SDL_Texture *texture; }; struct data { const char *plugin_dir; struct spa_log *log; struct spa_system *system; struct spa_loop *loop; struct spa_loop_control *control; struct spa_support support[5]; uint32_t n_support; struct spa_node *source; struct spa_hook listener; struct spa_io_buffers source_output[1]; SDL_Renderer *renderer; SDL_Window *window; SDL_Texture *texture; bool use_buffer; bool running; pthread_t thread; struct spa_buffer *bp[MAX_BUFFERS]; struct buffer buffers[MAX_BUFFERS]; unsigned int n_buffers; }; static int load_handle(struct data *data, struct spa_handle **handle, const char *lib, const char *name) { int res; void *hnd; spa_handle_factory_enum_func_t enum_func; uint32_t i; char *path = NULL; if ((path = spa_aprintf("%s/%s", data->plugin_dir, lib)) == NULL) { return -ENOMEM; } if ((hnd = dlopen(path, RTLD_NOW)) == NULL) { printf("can't load %s: %s\n", path, dlerror()); free(path); return -ENOENT; } free(path); if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) { printf("can't find enum function\n"); return -ENOENT; } for (i = 0;;) { const struct spa_handle_factory *factory; if ((res = enum_func(&factory, &i)) <= 0) { if (res != 0) printf("can't enumerate factories: %s\n", spa_strerror(res)); break; } if (factory->version < 1) continue; if (!spa_streq(factory->name, name)) continue; *handle = calloc(1, spa_handle_factory_get_size(factory, NULL)); if ((res = spa_handle_factory_init(factory, *handle, NULL, data->support, data->n_support)) < 0) { printf("can't make factory instance: %d\n", res); return res; } return 0; } return -EBADF; } static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name) { struct spa_handle *handle = NULL; void *iface; int res; if ((res = load_handle(data, &handle, lib, name)) < 0) return res; if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Node, &iface)) < 0) { printf("can't get interface %d\n", res); return res; } *node = iface; return 0; } static int on_source_ready(void *_data, int status) { struct data *data = _data; int res; struct buffer *b; void *sdata, *ddata; int sstride, dstride; int i; uint8_t *src, *dst; struct spa_data *datas; ``` -------------------------------- ### local-v4l2.c Example Source: https://docs.pipewire.org/local-v4l2_8c-example.html This C code example demonstrates how to use libspa-v4l2 with the SPA framework. It includes setup for video capture, buffer management, and rendering using SDL2. Ensure SDL2 development libraries are installed. ```c /* Spa */ /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ /* SPDX-License-Identifier: MIT */ /* [title] Example using libspa-v4l2, with only \ref api_spa [title] */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static SPA_LOG_IMPL(default_log); #define MAX_BUFFERS 8 #define LOOP_TIMEOUT_MS 100 struct buffer { struct spa_buffer buffer; struct spa_meta metas[1]; struct spa_meta_header header; struct spa_data datas[1]; struct spa_chunk chunks[1]; SDL_Texture *texture; }; struct data { const char *plugin_dir; struct spa_log *log; struct spa_system *system; struct spa_loop *loop; struct spa_loop_control *control; struct spa_support support[5]; uint32_t n_support; struct spa_node *source; struct spa_hook listener; struct spa_io_buffers source_output[1]; SDL_Renderer *renderer; SDL_Window *window; SDL_Texture *texture; bool use_buffer; bool running; pthread_t thread; struct spa_buffer *bp[MAX_BUFFERS]; struct buffer buffers[MAX_BUFFERS]; unsigned int n_buffers; }; static int load_handle(struct data *data, struct spa_handle **handle, const char *lib, const char *name) { int res; void *hnd; spa_handle_factory_enum_func_t enum_func; uint32_t i; char *path = NULL; if ((path = spa_aprintf("%s/%s", data->plugin_dir, lib)) == NULL) { return -ENOMEM; } if ((hnd = dlopen(path, RTLD_NOW)) == NULL) { printf("can't load %s: %s\n", path, dlerror()); free(path); return -ENOENT; } free(path); if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) { printf("can't find enum function\n"); return -ENOENT; } for (i = 0;;) { const struct spa_handle_factory *factory; if ((res = enum_func(&factory, &i)) <= 0) { if (res != 0) printf("can't enumerate factories: %s\n", spa_strerror(res)); break; } if (factory->version < 1) continue; if (!spa_streq(factory->name, name)) continue; *handle = calloc(1, spa_handle_factory_get_size(factory, NULL)); if ((res = spa_handle_factory_init(factory, *handle, NULL, data->support, data->n_support)) < 0) { printf("can't make factory instance: %d\n", res); return res; } return 0; } return -EBADF; } static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name) { struct spa_handle *handle = NULL; void *iface; int res; if ((res = load_handle(data, &handle, lib, name)) < 0) return res; if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Node, &iface)) < 0) { printf("can't get interface %d\n", res); return res; } *node = iface; return 0; } static int on_source_ready(void *_data, int status) { struct data *data = _data; int res; struct buffer *b; void *sdata, *ddata; int sstride, dstride; int i; uint8_t *src, *dst; struct spa_data *datas; ``` -------------------------------- ### Main Function for PipeWire Client Binding Example Source: https://docs.pipewire.org/page_tutorial6.html Initializes PipeWire, connects to the core, gets the registry, adds a listener, and runs the main loop. It cleans up resources upon exit. ```c int main(int argc, char *argv[]) { struct data data; spa_zero(data); pw_init(&argc, &argv); data.loop = pw_main_loop_new(NULL /* properties */ ); data.context = pw_context_new(pw_main_loop_get_loop(data.loop), NULL /* properties */ , 0 /* user_data size */ ); data.core = pw_context_connect(data.context, NULL /* properties */ , 0 /* user_data size */ ); data.registry = pw_core_get_registry(data.core, PW_VERSION_REGISTRY, 0 /* user_data size */ ); pw_registry_add_listener(data.registry, &data.registry_listener, ®istry_events, &data); pw_main_loop_run(data.loop); pw_proxy_destroy((struct pw_proxy *)data.client); pw_proxy_destroy((struct pw_proxy *)data.registry); pw_core_disconnect(data.core); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop); return 0; } ``` -------------------------------- ### Video Source with Sync Timeline Source: https://docs.pipewire.org/video-src-sync_8c-example.html This example demonstrates creating a video source using `pw_stream` and `sync_timeline`. It includes setup for the PipeWire core, stream, and buffer processing logic. The code handles buffer dequeuing, filling with sample data, and metadata updates, including synchronization points. ```c /* PipeWire */ /* SPDX-FileCopyrightText: Copyright © 2025 Wim Taymans */ /* SPDX-License-Identifier: MIT */ /* [title] Video source using \ref pw_stream and sync_timeline. [title] */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BPP 4 #define CURSOR_WIDTH 64 #define CURSOR_HEIGHT 64 #define CURSOR_BPP 4 #define MAX_BUFFERS 64 #define M_PI_M2 ( M_PI + M_PI ) struct data { struct pw_main_loop *loop; struct spa_source *timer; struct pw_context *context; struct pw_core *core; struct pw_stream *stream; struct spa_hook stream_listener; struct spa_video_info_raw format; int32_t stride; int counter; uint32_t seq; uint32_t n_buffers; int res; bool with_synctimeline; bool with_synctimeline_release; bool force_synctimeline_release; }; static void on_process(void *userdata) { struct data *data = userdata; struct pw_buffer *b; struct spa_buffer *buf; uint32_t i, j; uint8_t *p; struct spa_meta_header *h; struct spa_meta_sync_timeline *stl; uint64_t cmd; if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) { pw_log_warn("out of buffers: %m"); return; } buf = b->buffer; if ((p = buf->datas[0].data) == NULL) return; if ((h = spa_buffer_find_meta_data(buf, SPA_META_Header, sizeof(*h)))) { #if 0 h->pts = pw_stream_get_nsec(data->stream); #else h->pts = -1; #endif h->flags = 0; h->seq = data->seq++; h->dts_offset = 0; } if ((stl = spa_buffer_find_meta_data(buf, SPA_META_SyncTimeline, sizeof(*stl))) && stl->release_point) { if (!SPA_FLAG_IS_SET(stl->flags, SPA_META_SYNC_TIMELINE_UNSCHEDULED_RELEASE)) { /* The other end promised to schedule the release point, wait before we * can use the buffer */ if (read(buf->datas[2].fd, &cmd, sizeof(cmd)) < 0) pw_log_warn("release_point wait error %m"); pw_log_debug("release_point:%"PRIu64, stl->release_point); } else if (spa_buffer_has_meta_features(buf, SPA_META_SyncTimeline, SPA_META_FEATURE_SYNC_TIMELINE_RELEASE)) { /* this happens when the other end did not get the buffer or * will not trigger the release point, There is no point waiting, * we can use the buffer right away */ pw_log_warn("release_point not scheduled:%"PRIu64, stl->release_point); } else { /* The other end does not support the RELEASE flag, we don't * know if the buffer was used or not or if the release point will * ever be scheduled, we must assume we can reuse the buffer */ pw_log_debug("assume buffer was released:%"PRIu64, stl->release_point); } } for (i = 0; i < data->format.size.height; i++) { for (j = 0; j < data->format.size.width * BPP; j++) p[j] = data->counter + j * i; p += data->stride; data->counter += 13; } buf->datas[0].chunk->offset = 0; buf->datas[0].chunk->size = data->format.size.height * data->stride; buf->datas[0].chunk->stride = data->stride; if (stl) { /* set the UNSCHEDULED_RELEASE flag, the consumer will clear this if * it promises to signal the release point */ SPA_FLAG_SET(stl->flags, SPA_META_SYNC_TIMELINE_UNSCHEDULED_RELEASE); cmd = 1; ``` -------------------------------- ### Example Usage of pw_client_info_update Source: https://docs.pipewire.org/client_8h_source.html Illustrative example showing how to call pw_client_info_update. Note: This is a placeholder and requires actual data. ```c pw_client_info_update(struct pw_client_info *info, {…}; ``` -------------------------------- ### Example Drop-in Configuration File Source: https://docs.pipewire.org/page_man_pipewire_conf_5.html This example shows how to create a drop-in configuration file to modify a specific setting, such as the default clock quantum, in PipeWire. ```shell # ~/.config/pipewire/pipewire.conf.d/custom.conf context.properties = { default.clock.min-quantum = 128 } ``` -------------------------------- ### PipeWire API Tutorial Examples Source: https://docs.pipewire.org/page_examples.html This section lists C code examples that correspond to the PipeWire API Tutorial. These examples cover various aspects of PipeWire programming, from basic setup to advanced features. ```c tutorial1.c: Tutorial - Part 1: Getting Started ``` ```c tutorial2.c: Tutorial - Part 2: Enumerating Objects ``` ```c tutorial3.c: Tutorial - Part 3: Forcing A Roundtrip ``` ```c tutorial4.c: Tutorial - Part 4: Playing A Tone ``` ```c tutorial5.c: Tutorial - Part 5: Capturing Video Frames ``` ```c tutorial6.c: Tutorial - Part 6: Binding Objects ``` ```c tutorial7.c: Tutorial - Part 7: Creating an Audio DSP Filter ``` -------------------------------- ### Main function for PipeWire example Source: https://docs.pipewire.org/spa_2examples_2example-control_8c-example.html The main function initializes data, creates nodes, and negotiates audio formats. This is the entry point for the example application. ```c int main(int argc, char *argv[]) { struct data data = { NULL }; int res; if ((res = init_data(&data)) < 0) { printf("can't init data: %d (%s)\n", res, spa_strerror(res)); return -1; } if ((res = make_nodes(&data, argc > 1 ? argv[1] : NULL)) < 0) { printf("can't make nodes: %d (%s)\n", res, spa_strerror(res)); return -1; } if ((res = negotiate_formats(&data)) < 0) { printf("can't negotiate nodes: %d (%s)\n", res, spa_strerror(res)); return -1; } ``` -------------------------------- ### Loading Example Filter Module via pw-cli Source: https://docs.pipewire.org/page_module_example_filter.html This command demonstrates how to load the example filter module dynamically using the pw-cli tool, specifying audio channel positions as an argument. ```shell pw-cli -m lm libpipewire-module-example-filter '{ audio.position=[FL FR] }' ``` -------------------------------- ### Start BlueZ Monitor Source: https://docs.pipewire.org/bluez-session_8c-example.html Starts the monitoring process for BlueZ devices. It loads the D-Bus enumeration handle, gets the device interface, and adds a listener for device events. ```c static int start_monitor(struct impl *impl) { struct spa_handle *handle; int res; void *iface; handle = pw_context_load_spa_handle(impl->context, SPA_NAME_API_BLUEZ5_ENUM_DBUS, &impl->props->dict); if (handle == NULL) { res = -errno; goto out; } if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) { pw_log_error("can't get MONITOR interface: %d", res); goto out_unload; } impl->handle = handle; impl->device = iface; spa_device_add_listener(impl->device, &impl->listener, &dbus_device_events, impl); return 0; out_unload: pw_unload_spa_handle(handle); out: return res; } ``` -------------------------------- ### Free PipeWire Client Info Example Source: https://docs.pipewire.org/client_8h_source.html Example demonstrating the freeing of a pw_client_info structure. This is a stub and requires actual data. ```c void pw_client_info_free(struct pw_client_info *info) Free a pw_client_info. **Definition** introspect.c:513 ``` -------------------------------- ### Example Portal Module Configuration Source: https://docs.pipewire.org/page_module_portal.html This is an example of how to load the libpipewire-module-portal in a PipeWire configuration file. Ensure this snippet is placed within the 'context.modules' array. ```configuration context.modules = [ { name = libpipewire-module-portal } ] ``` -------------------------------- ### ALSA Client Rules Example Source: https://docs.pipewire.org/page_man_pipewire-client_conf_5.html Example of setting ALSA client-specific properties using rules in a configuration file. This example targets the 'resolve' application. ```shell alsa.rules = [ { matches = [ { application.process.binary = "resolve" } ] actions = { update-props = { alsa.buffer-bytes = 131072 } } } ] ``` -------------------------------- ### PipeWire SPA Examples Source: https://docs.pipewire.org/page_examples.html A collection of examples demonstrating various SPA functionalities, including adapter control, local libcamera, local v4l2, and local videotestsrc. ```c spa/examples/adapter-control.c: Running audioadapter nodes. ``` ```c spa/examples/example-control.c: ``` ```c spa/examples/local-libcamera.c: Example using libspa-libcamera, with only SPA ``` ```c spa/examples/local-v4l2.c: Example using libspa-v4l2, with only SPA ``` ```c spa/examples/local-videotestsrc.c: Example using libspa-videotestsrc, with only SPA ``` -------------------------------- ### PipeWire SPA v4l2 Example Source: https://docs.pipewire.org/page_examples.html Example using libspa-v4l2, demonstrating its usage with only SPA components. ```c local-v4l2.c: Example using libspa-v4l2, with only SPA ``` -------------------------------- ### PipeWire Internal Graph Example Source: https://docs.pipewire.org/page_examples.html An example demonstrating an in-process PipeWire graph. ```c internal.c: In process pipewire graph ``` -------------------------------- ### Example Filter Configuration Source: https://docs.pipewire.org/page_module_example_filter.html This configuration snippet shows how to load the example filter module in pipewire.conf.d. It sets a description for the filter and specifies properties for both capture and playback streams, including audio channel positions and media class. ```configuration context.modules = [ { name = libpipewire-module-example-filter args = { node.description = "Example Filter" capture.props = { audio.position = [ FL FR ] node.passive = true } playback.props = { node.name = "Example Filter" media.class = "Audio/Source" audio.position = [ FL FR ] } } } ] ``` -------------------------------- ### Example Sink Configuration Source: https://docs.pipewire.org/page_module_example_sink.html This configuration snippet shows how to load and configure the example sink module in PipeWire. It sets a unique node name, a human-readable description, and specific audio stream properties. ```configuration context.modules = [ { name = libpipewire-module-example-sink args = { node.name = "example_sink" node.description = "My Example Sink" stream.props = { audio.position = [ FL FR ] } } } ] ``` -------------------------------- ### PipeWire BlueZ Session Example Source: https://docs.pipewire.org/page_examples.html An example demonstrating the use of the SPA Device API, among other things, for BlueZ sessions. ```c bluez-session.c: Using the SPA Device API, among other things. ``` -------------------------------- ### PipeWire Video Playback Examples Source: https://docs.pipewire.org/page_examples.html Examples for handling video input streams using pw_stream and pw_filter. Includes variations for pull mode, renegotiation, and synchronization. ```c video-play.c: Video input stream using pw_stream. ``` ```c video-dsp-play.c: Video input stream using pw_filter. ``` ```c video-play-pull.c: Video input stream using pw_stream_trigger_process, for pull mode. ``` ```c video-play-reneg.c: Video input stream using pw_stream, with format renegotiation. ``` ```c video-play-sync.c: Video input stream using pw_stream and sync timeline. ``` ```c video-play-fixate.c: Video input stream using pw_stream, with format fixation. ``` -------------------------------- ### spa_type_param_availability Example (Partial) Source: https://docs.pipewire.org/param-types_8h_source.html A partial example showing the structure of the spa_type_param_availability array, indicating its use with unknown, no, and yes states. ```c { SPA_PARAM_AVAILABILITY_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "unknown", NULL }, {…}; ``` -------------------------------- ### LV2 Plugin with State Example Source: https://docs.pipewire.org/page_module_filter_chain.html Example of configuring an LV2 plugin with specific controls and state. Ensure the plugin path and control symbols are correct. ```lua { # an example lv2 plugin with a state type = lv2 name = neural plugin = "http://aidadsp.cc/plugins/aidadsp-bundle/rt-neural-generic" control = { # use the port symbols as seen with lv2info PRESENCE = 1.0 } config = { # the config contains state keys and values "http://aidadsp.cc/plugins/aidadsp-bundle/rt-neural-generic#json" = "/usr/lib64/lv2/rt-neural-generic.lv2/models/deer ink studios/tw40_blues_solo_deerinkstudios.json" } } ``` -------------------------------- ### PipeWire Audio Source Examples Source: https://docs.pipewire.org/page_examples.html Examples demonstrating audio source implementations using PipeWire's pw_stream and pw_filter APIs. Includes variations with ringbuffers and thread loops. ```c audio-src.c: Audio source using pw_stream. ``` ```c audio-src-ring.c: Audio source using pw_stream and ringbuffer. ``` ```c audio-src-ring2.c: Audio source using pw_stream and ringbuffer. This one uses a thread-loop and does a blocking push into a ringbuffer. ``` ```c audio-dsp-src.c: Audio source using pw_filter ``` -------------------------------- ### Video Playback Example (video-play.c) Source: https://docs.pipewire.org/page_tutorial.html Illustrates how to set up a video input stream using pw_stream. ```c video-play.c: Video input stream using pw_stream. ``` -------------------------------- ### Basic PipeWire Pulse Module Setup Source: https://docs.pipewire.org/page_module_protocol_pulse.html This configuration snippet shows the minimal setup for loading the pipewire-module-protocol-pulse and setting basic pulse properties, including the server address. ```configuration context.modules = [ { name = libpipewire-module-protocol-pulse args = { } } ] pulse.properties = { server.address = [ "unix:native" ] } pulse.rules = [ { # skype does not want to use devices that don't have an S16 sample format. matches = [ { application.process.binary = "teams" } { application.process.binary = "teams-insiders" } { application.process.binary = "skypeforlinux" } ] actions = { quirks = [ force-s16-info ] } } { # speech dispatcher asks for too small latency and then underruns. matches = [ { application.name = "~speech-dispatcher*" } ] actions = { update-props = { pulse.min.req = 1024/48000 # 21ms pulse.min.quantum = 1024/48000 # 21ms pulse.idle.timeout = 5 # pause after 5 seconds of underrun } } } ] ``` -------------------------------- ### Full PipeWire rt Module Configuration Example Source: https://docs.pipewire.org/page_module_rt.html This example provides a complete configuration for the libpipewire-module-rt, including various arguments for controlling thread priorities, CPU time limits, and resource limit behavior. It also specifies flags for module loading. ```INI context.modules = [ { name = libpipewire-module-rt args = { #nice.level = 20 #rt.prio = 88 #rt.time.soft = -1 #rt.time.hard = -1 #rlimits.enabled = true #rtportal.enabled = true #rtkit.enabled = true #uclamp.min = 0 #uclamp.max = 1024 } flags = [ ifexists nofail ] } ] ``` -------------------------------- ### Compile the Tutorial Application Source: https://docs.pipewire.org/page_tutorial3.html Use this command to compile the tutorial3.c file. Ensure you have libpipewire-0.3 installed. ```bash gcc -Wall tutorial3.c -o tutorial3 $(pkg-config --cflags --libs libpipewire-0.3) ``` -------------------------------- ### spa_meta_first and spa_meta_end Functions Source: https://docs.pipewire.org/meta_8h_source.html Utility functions to get the start and end pointers of the metadata payload. ```c SPA_API_META void *spa_meta_first(const struct spa_meta *m) { return m->data; } SPA_API_META void *spa_meta_end(const struct spa_meta *m) { return SPA_PTROFF(m->data,m->size,void); } ``` -------------------------------- ### Load Module Command Example Source: https://docs.pipewire.org/page_module_protocol_pulse.html Demonstrates how to load modules during server startup using the `load-module` command with arguments. The `nofail` flag ensures the server continues even if the module fails to load. ```shell pulse.cmd = [ { cmd = "load-module" args = "module-always-sink" flags = [] } ] # Example with condition: #{ cmd = "load-module" args = "module-switch-on-connect" condition = [ { pulse.cmd.switch-on-connect = true } ] # Example with nofail flag: #{ cmd = "load-module" args = "module-gsettings" flags = [ "nofail" ] } ``` -------------------------------- ### PipeWire Exporting SPA Node Examples Source: https://docs.pipewire.org/page_examples.html Examples showing how to export and implement SPA nodes (including devices) using the PipeWire Core API. ```c export-sink.c: Exporting and implementing a video sink SPA node, using Core API. ``` ```c export-source.c: Exporting and implementing a video source SPA node, using Core API. ``` ```c export-spa.c: Exporting and loading a SPA node, using Core API. ``` ```c export-spa-device.c: Exporting and loading a SPA device, using Core API. ``` -------------------------------- ### Get PipeWire Client Permissions Source: https://docs.pipewire.org/client_8h_source.html Requests permissions for a PipeWire client, starting from a given index. This is a wrapper around spa_api_method_r. ```c /** \sa pw_client_methods.get_permissions */ PW_API_CLIENT_IMPL int pw_client_get_permissions(struct pw_client *object, uint32_t index, uint32_t num) { return spa_api_method_r(int, -ENOTSUP, pw_client, (struct spa_interface*)object, get_permissions, 0, index, num); } ``` -------------------------------- ### Get JSON Container Length Source: https://docs.pipewire.org/group__spa__json.html Calculates the length of a JSON container (object or array) starting at the given value. 'len1' is typically the length of the container string itself. ```c SPA_API_JSON_UTILS int | spa_json_container_len (struct spa_json *iter, const char *value, int len1) ``` -------------------------------- ### Compiling the PipeWire Example Source: https://docs.pipewire.org/page_tutorial6.html Command to compile the tutorial6.c file using gcc, linking against the libpipewire-0.3 library. ```bash gcc -Wall tutorial6.c -o tutorial6 $(pkg-config --cflags --libs libpipewire-0.3) ``` -------------------------------- ### SPA Handle Factory Get Size Example Source: https://docs.pipewire.org/structspa__handle__factory.html Shows the function signature for retrieving the required size for a SPA handle instance from a factory, potentially based on parameters. ```c size_t(*get_size)(const struct spa_handle_factory *factory, const struct spa_dict *params) ``` -------------------------------- ### Initialize PipeWire and Setup Properties Source: https://docs.pipewire.org/video-play-fixate_8c-example.html Initializes the PipeWire library and prepares properties for a PipeWire client. This is the entry point for setting up PipeWire communication. ```c int main(int argc, char *argv[]) { struct data data = { 0, }; const struct spa_pod *params[MAX_PARAMS]; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct spa_pod_frame f; struct pw_properties *props; int res, n_params = 0; SDL_RendererInfo info; pw_init(&argc, &argv); ``` -------------------------------- ### Setting PipeWire ALSA Properties via Environment Variable Source: https://docs.pipewire.org/page_man_pipewire-client_conf_5.html Example of starting an ALSA application with custom PipeWire ALSA properties using the PIPEWIRE_ALSA environment variable. ```shell PIPEWIRE_ALSA='{ alsa.buffer-bytes=16384 node.name=foo }' aplay ... ``` -------------------------------- ### Example SPA Interface Initialization Source: https://docs.pipewire.org/group__spa__interfaces.html Demonstrates initializing a SPA interface using the SPA_INTERFACE_INIT macro. ```c const static struct foo_methods foo_funcs = { .bar = some_bar_implementation, }; struct foo *f = malloc(...); f->iface = SPA_INTERFACE_INIT("foo type", 0, foo_funcs, NULL); ``` -------------------------------- ### Get first property of a POD object Source: https://docs.pipewire.org/iter_8h_source.html Retrieves a pointer to the first property within a POD object's body. This is the starting point for iterating through an object's properties. ```c SPA_API_POD_ITER struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body) { return SPA_PTROFF(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop); } ``` -------------------------------- ### Snapcast Discover Module Configuration Example Source: https://docs.pipewire.org/page_module_snapcast_discover.html This configuration snippet shows how to load the snapcast discover module and define rules for creating streams. It includes options for matching snapcast server properties and actions to create new streams. ```conf context.modules = [ { name = libpipewire-module-snapcast-discover args = { stream.rules = [ { matches = [ { snapcast.ip = "~.*" #snapcast.port = 1000 #snapcast.ifindex = 1 #snapcast.ifname = eth0 #snapcast.name = "" #snapcast.hostname = "" #snapcast.domain = "" } ] actions = { create-stream = { #audio.rate = 44100 #audio.format = S16LE # S16LE, S24_32LE, S32LE #audio.channels = 2 #audio.position = [ FL FR ] # # The stream name as is appears on the snapcast # server: #snapcast.stream-name = "PipeWire" # # The name of the sink on the sender: #node.name = "Snapcast Sink" # #capture = true #server.address = [ "tcp:4711" ] #capture.props = { #target.object = "" #node.latency = 2048/48000 #media.class = "Audio/Sink" #} } } } ] } } ] # See also Protocol Simple ``` -------------------------------- ### Run asynchronous sink with thread creation Source: https://docs.pipewire.org/spa_2examples_2example-control_8c-example.html Starts an asynchronous sink, creates a new thread for the loop, and then pauses the sink. This example shows managing threads and node states. ```c static void run_async_sink(struct data *data) { int res, err; struct spa_command cmd; cmd = SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_Start); if ((res = spa_node_send_command(data->sink, &cmd)) < 0) printf("got error %d\n", res); spa_loop_control_leave(data->control); data->running = true; if ((err = pthread_create(&data->thread, NULL, loop, data)) != 0) { printf("can't create thread: %d %s", err, strerror(err)); data->running = false; } printf("sleeping for 1000 seconds\n"); sleep(1000); if (data->running) { data->running = false; pthread_join(data->thread, NULL); } spa_loop_control_enter(data->control); cmd = SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_Pause); if ((res = spa_node_send_command(data->sink, &cmd)) < 0) printf("got error %d\n", res); } ``` -------------------------------- ### Pulse Protocol Module Configuration Example Source: https://docs.pipewire.org/page_module_protocol_pulse.html This example shows how to configure the pulse protocol module with custom rules for applications like Teams and Skype, and for speech dispatchers. It demonstrates the use of 'quirks' and 'update-props' actions. ```configuration pulse.rules = [ { # skype does not want to use devices that don't have an S16 sample format. matches = [ { application.process.binary = "teams" } { application.process.binary = "teams-insiders" } { application.process.binary = "skypeforlinux" } ] actions = { quirks = [ force-s16-info ] } } { # speech dispatcher asks for too small latency and then underruns. matches = [ { application.name = "~speech-dispatcher*" } ] actions = { update-props = { pulse.min.req = 1024/48000 # 21ms pulse.min.quantum = 1024/48000 # 21ms pulse.idle.timeout = 5 # pause after 5 seconds of underrun } } } ] ``` -------------------------------- ### SPA Hook Example Structure Source: https://docs.pipewire.org/group__spa__hooks.html Defines the structure for event callbacks and a private implementation structure that holds a list of hooks. This illustrates the basic setup for using SPA hooks. ```c #define VERSION_BAR_EVENTS 0 // version of the vtable struct bar_events { uint32_t version; // NOTE: an integral member named `version` // must be present in the vtable void (*boom)(void *data, const char *msg); }; // private implementation struct party { struct spa_hook_list bar_list; }; void party_add_event_listener(struct party *p, struct spa_hook *listener, const struct bar_events *events, void *data) { spa_hook_list_append(&p->bar_list, listener, events, data); } static void party_on(struct party *p) { // NOTE: this is a macro, it evaluates to an integer, // which is the number of hooks called spa_hook_list_call(&p->list, struct bar_events, // vtable type boom, // function name 0, // hardcoded version, // usually the version in which `boom` // has been added to the vtable "party on, wayne" // function argument(s) ); } ``` -------------------------------- ### Main function for PipeWire audio source setup Source: https://docs.pipewire.org/audio-src-ring_8c-example.html Initializes PipeWire, sets up the main loop, signal handlers, ring buffer, and creates/connects a new audio stream. This is the entry point of the application. ```c int main(int argc, char *argv[]) { struct data data = { 0, }; const struct spa_pod *params[1]; uint32_t n_params = 0; uint8_t buffer[1024]; struct pw_properties *props; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); pw_init(&argc, &argv); data.main_loop = pw_main_loop_new(NULL); data.loop = pw_main_loop_get_loop(data.main_loop); pw_loop_add_signal(data.loop, SIGINT, do_quit, &data); pw_loop_add_signal(data.loop, SIGTERM, do_quit, &data); /* we're going to refill a ringbuffer from the main loop. Make an * event for this. */ spa_ringbuffer_init(&data.ring); data.refill_event = pw_loop_add_event(data.loop, do_refill, &data); /* prefill the ringbuffer */ do_refill(&data, 0); props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Playback", PW_KEY_MEDIA_ROLE, "Music", NULL); if (argc > 1) /* Set stream target if given on command line */ pw_properties_set(props, PW_KEY_TARGET_OBJECT, argv[1]); data.stream = pw_stream_new_simple( data.loop, "audio-src-ring", props, &stream_events, &data); /* Make one parameter with the supported formats. The SPA_PARAM_EnumFormat * id means that this is a format enumeration (of 1 value). */ params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &SPA_AUDIO_INFO_RAW_INIT( .format = SPA_AUDIO_FORMAT_F32, .channels = DEFAULT_CHANNELS, .rate = DEFAULT_RATE )); /* Now connect this stream. We ask that our process function is * called in a realtime thread. */ pw_stream_connect(data.stream, PW_DIRECTION_OUTPUT, PW_ID_ANY, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS, params, n_params); /* and wait while we let things run */ pw_main_loop_run(data.main_loop); pw_stream_destroy(data.stream); pw_loop_destroy_source(data.loop, data.refill_event); pw_main_loop_destroy(data.main_loop); pw_deinit(); return 0; } ``` -------------------------------- ### PipeWire Video Source Examples Source: https://docs.pipewire.org/page_examples.html Code examples for implementing video sources using PipeWire's Stream and Stream APIs. Includes synchronization and buffer memory allocation. ```c video-src.c: Video source using Stream. ``` ```c video-src-sync.c: Video source using Stream and sync_timeline. ``` ```c video-dsp-src.c: Video source using Stream. ``` ```c video-src-alloc.c: Allocating buffer memory and sending fds to the server. ``` ```c video-src-reneg.c: Renegotiating video producer and consumer formats with Stream ``` ```c video-src-fixate.c: Fixating negotiated modifiers. ``` -------------------------------- ### Parametric Equalizer Configuration Example Source: https://docs.pipewire.org/page_module_parametric_equalizer.html This is an example of a parametric equalizer configuration file format, often generated by AutoEQ or Squiglink projects. It specifies preamp and filter settings (frequency, gain, Q, and type). ```text Preamp: -6.8 dB Filter 1: ON PK Fc 21 Hz Gain 6.7 dB Q 1.100 Filter 2: ON PK Fc 85 Hz Gain 6.9 dB Q 3.000 Filter 3: ON PK Fc 110 Hz Gain -2.6 dB Q 2.700 Filter 4: ON PK Fc 210 Hz Gain 5.9 dB Q 2.100 Filter 5: ON PK Fc 710 Hz Gain -1.0 dB Q 0.600 Filter 6: ON PK Fc 1600 Hz Gain 2.3 dB Q 2.700 ``` -------------------------------- ### Example Netjack2 Driver Configuration Source: https://docs.pipewire.org/page_module_netjack2_driver.html This configuration snippet shows how to set up the libpipewire-module-netjack2-driver in the PipeWire configuration file. It demonstrates setting client name, latency, MIDI and audio ports, and audio channel properties. Use this to integrate Netjack2 audio streaming into your PipeWire setup. ```text context.modules = [ { name = libpipewire-module-netjack2-driver args = { #netjack2.client-name = PipeWire #netjack2.latency = 2 #midi.ports = 0 #audio.ports = -1 #audio.channels = 2 #audio.position = [ FL FR ] source.props = { # extra source properties } sink.props = { # extra sink properties } } } ] ``` -------------------------------- ### Initiate Core Hello Source: https://docs.pipewire.org/group__pw__core.html Starts a conversation with the PipeWire server by sending core information. This requires X permissions on the core and may destroy client resources. ```c PW_API_CORE_IMPL int pw_core_hello(struct pw_core * _object_, uint32_t _version_) ``` -------------------------------- ### Main Function and Initialization Source: https://docs.pipewire.org/video-src-reneg_8c-example.html Initializes PipeWire, sets up a thread loop, signal handlers for graceful exit, and creates a simple video source stream. ```c int main(int argc, char *argv[]) { struct data data = { 0, }; const struct spa_pod *params[1]; uint32_t n_params = 0; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); pw_init(&argc, &argv); /* create a thread loop and start it */ data.loop = pw_thread_loop_new("video-src-reneg", NULL); /* take the lock around all PipeWire functions. In callbacks, the lock * is already taken for you but it's ok to lock again because the lock is * recursive */ pw_thread_loop_lock(data.loop); /* install some handlers to exit nicely */ pw_loop_add_signal(pw_thread_loop_get_loop(data.loop), SIGINT, do_quit, &data); pw_loop_add_signal(pw_thread_loop_get_loop(data.loop), SIGTERM, do_quit, &data); /* start after the signal handlers are set */ pw_thread_loop_start(data.loop); /* create a simple stream, the simple stream manages the core * object for you if you don't want to deal with them. * * We're making a new video provider. We need to set the media-class * property. * * Pass your events and a user_data pointer as the last arguments. This * will inform you about the stream state. The most important event * you need to listen to is the process event where you need to provide * the data. */ data.stream = pw_stream_new_simple( pw_thread_loop_get_loop(data.loop), "video-src-alloc", pw_properties_new( PW_KEY_MEDIA_CLASS, "Video/Source", NULL), &stream_events, &data); /* make a timer to schedule our frames */ data.timer = pw_loop_add_timer(pw_thread_loop_get_loop(data.loop), on_timeout, &data); /* make a timer to schedule renegotiation */ data.reneg_timer = pw_loop_add_timer(pw_thread_loop_get_loop(data.loop), on_reneg_timeout, &data); /* build the extra parameter for the connection. Here we make an * EnumFormat parameter which lists the possible formats we can provide. * The server will select a format that matches and informs us about this * in the stream param_changed event. */ params[n_params++] = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), ``` -------------------------------- ### Call Hook List (Start) Source: https://docs.pipewire.org/hook_8h.html Calls hooks in a list starting from a specified hook. This macro provides control over the starting point of the call. ```c #define spa_hook_list_call_start(l, s, t, m, v, ...) ``` -------------------------------- ### PipeWire Initialization and Connection Source: https://docs.pipewire.org/page_tutorial2.html This C code snippet demonstrates the basic setup for a PipeWire client application, including initialization, creating a main loop, context, and connecting to the PipeWire daemon. ```c #include 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[]) { struct pw_main_loop *loop; struct pw_context *context; struct pw_core *core; struct pw_registry *registry; struct spa_hook registry_listener; pw_init(&argc, &argv); loop = pw_main_loop_new(NULL /* properties */); context = pw_context_new(pw_main_loop_get_loop(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); pw_main_loop_run(loop); pw_proxy_destroy((struct pw_proxy*)registry); pw_core_disconnect(core); pw_context_destroy(context); pw_main_loop_destroy(loop); return 0; } ``` -------------------------------- ### Get Domain Source: https://docs.pipewire.org/group__pw__pipewire.html Gets the current PipeWire domain. ```c const char * pw_get_domain (void) ```