mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-07-21 10:16:14 +00:00
Documentation Updates
This commit is contained in:
parent
8afe5fe0f0
commit
c71db353f1
|
@ -1,15 +1,16 @@
|
|||
/** \page page_dma_buf DMA-BUF sharing
|
||||
/** \page page_dma_buf DMA-BUF Sharing
|
||||
|
||||
PipeWire supports sharing Direct Memory Access buffers (DMA-BUFs) between
|
||||
clients via the `SPA_DATA_DmaBuf` data type. However properly negotiating
|
||||
DMA-BUF support on both the producer and the consumer side require following
|
||||
a specific procedure. This page describes said procedure by using events and
|
||||
methods from the filter or stream API.
|
||||
|
||||
Note: This article focuses mostly on DMA-BUF sharing from arbitrary devices,
|
||||
like discrete GPUs. For using DMA-BUFs created by v4l2 please refer to the
|
||||
corresponding paragraph.
|
||||
|
||||
# Capability negotiations
|
||||
# Capability Negotiations
|
||||
|
||||
The capability negotiation for DMA-BUFs is complicated by the fact, that a
|
||||
usable and preferred optimal modifier for a given format can only be
|
||||
|
@ -40,7 +41,7 @@ property.
|
|||
To prioritise DMA-BUFs place those `SPA_PARAM_EnumFormat` containing modifiers
|
||||
first, when emitting them to PipeWire.
|
||||
|
||||
## param_changed hook
|
||||
## param_changed Hook
|
||||
|
||||
When the `param_changed` hook is called for a `SPA_PARAM_Format` the client
|
||||
has to parse the `spa_pod` directly. Use
|
||||
|
@ -57,15 +58,15 @@ format modifier pair. The producer is also responsible to check if all clients
|
|||
announce sufficient capabilities or fallback to shared memory buffers when
|
||||
possible.
|
||||
|
||||
### For consumers
|
||||
### For Consumers
|
||||
|
||||
Use `spa_format_video_raw_parse` to get the format and modifier.
|
||||
|
||||
### For producers
|
||||
### For Producers
|
||||
|
||||
Producers have to handle two cases when it comes to modifiers wrt. to the
|
||||
previous announced capabilities: Using only the modifier-less API, only the
|
||||
modifier aware one, or supporting both.
|
||||
modifier-aware one, or supporting both.
|
||||
|
||||
- modifier-less:
|
||||
In this case only the modifier `DRM_FORMAT_MOD_INVALID` was announced with
|
||||
|
@ -77,12 +78,12 @@ modifier aware one, or supporting both.
|
|||
In this case a list with all supported modifiers will be returned in the format.
|
||||
(using `DRM_FORMAT_MOD_INVALID` as the token for the modifier-less API).
|
||||
On the `param_changed` event check if the modifier key is present and has the flag
|
||||
`SPA_POD_PROP_FLAG_DONT_FIXATE`. attached to it. In this case extract all modifiers
|
||||
`SPA_POD_PROP_FLAG_DONT_FIXATE` attached to it. In this case extract all modifiers
|
||||
from the list and do a test allocation with your allocator to choose the preferred
|
||||
modifier. Fixate on that `EnumFormat` by announcing a `SPA_PARAM_EnumFormat` with
|
||||
only one modifier in the `SPA_CHOICE_Enum` and without the
|
||||
`SPA_POD_PROP_FLAG_DONT_FIXATE` flag, followed by the previous announced
|
||||
`EnumFormat`s. This will retrigger the `param_changed` event with an
|
||||
`EnumFormat`. This will retrigger the `param_changed` event with an
|
||||
`SPA_PARAM_Format` as described below.
|
||||
If the `SPA_PARAM_Format` contains a modifier key, without the flag
|
||||
`SPA_POD_PROP_FLAG_DONT_FIXATE`, it should only contain one value in the
|
||||
|
@ -96,32 +97,32 @@ pass them all to the graphics API. If the allocation fails and the list of
|
|||
possible modifiers contains `DRM_FORMAT_MOD_INVALID`, fall back to allocating
|
||||
without an explicit modifier if the graphics API allows it.
|
||||
|
||||
## add_buffer hook
|
||||
## add_buffer Hook
|
||||
|
||||
This is relevant for producers.
|
||||
|
||||
Allocate a DMA-BUF only using the negotiated format and modifier.
|
||||
|
||||
## on_event hook
|
||||
## on_event Hook
|
||||
|
||||
This is relevant for consumers.
|
||||
|
||||
Check the type of the dequeued buffer. If its `SPA_DATA_MemFd` or
|
||||
`SPA_DATA_MemPtr` use the fallback SHM import mechanism.
|
||||
If it's `SPA_DATA_DmaBuf`:
|
||||
Get the DMA-BUF FDs (the plane count is encoded in the `n_datas` variable of the
|
||||
If it's `SPA_DATA_DmaBuf`
|
||||
get the DMA-BUF FDs (the plane count is encoded in the `n_datas` variable of the
|
||||
`spa_buffer` struct) and import them with the graphics API.
|
||||
|
||||
Note: Some graphics APIs have separated functions for the modifier-less case
|
||||
(`DRM_FORMAT_MOD_INVALID`) or are omitting the modifier, since it might be used
|
||||
for error handling.
|
||||
|
||||
## Example programs
|
||||
## Example Programs
|
||||
|
||||
- \ref video-src-fixate.c "": \snippet{doc} video-src-fixate.c title
|
||||
- \ref video-play-fixate.c "": \snippet{doc} video-play-fixate.c title
|
||||
|
||||
# DMA-BUF mapping warning
|
||||
# DMA-BUF Mapping Warning
|
||||
|
||||
It's important to make sure all consumers of the PipeWire stream are prepared
|
||||
to deal with DMA-BUFs. Most DMA-BUFs cannot be treated like shared memory in general
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
/** \mainpage PipeWire
|
||||
|
||||
PipeWire is low-level multimedia framework that provides:
|
||||
- Graph based processing
|
||||
- Support for out-of-process processing graphs with minimal overhead
|
||||
- Flexible and extensible media format negotiation and buffer allocation
|
||||
- Hard real-time capable plugins
|
||||
- Very low-latency for both audio and video processing
|
||||
|
||||
- Graph based processing.
|
||||
- Support for out-of-process processing graphs with minimal overhead.
|
||||
- Flexible and extensible media format negotiation and buffer allocation.
|
||||
- Hard real-time capable plugins.
|
||||
- Very low-latency for both audio and video processing.
|
||||
|
||||
See \ref page_overview for an overview of PipeWire and \ref page_design
|
||||
for the design principles guiding PipeWire.
|
||||
|
||||
### Components
|
||||
# Components
|
||||
|
||||
PipeWire ships with the following components:
|
||||
|
||||
- a \ref page_daemon that implements the IPC and graph processing
|
||||
- an example \ref page_session_manager that manages objects in the \ref page_daemon
|
||||
- a set of \ref page_tools to introspect and use the \ref page_daemon
|
||||
- a \ref page_library to develop PipeWire applications and plugins (\ref
|
||||
- A \ref page_daemon that implements the IPC and graph processing.
|
||||
- An example \ref page_session_manager that manages objects in the \ref page_daemon.
|
||||
- A set of \ref page_tools to introspect and use the \ref page_daemon.
|
||||
- A \ref page_library to develop PipeWire applications and plugins (\ref
|
||||
page_tutorial "tutorial").
|
||||
- the \ref page_spa used by both the \ref page_daemon and in the \ref
|
||||
- The \ref page_spa used by both the \ref page_daemon and in the \ref
|
||||
page_library.
|
||||
|
||||
### API Documentation
|
||||
# API Documentation
|
||||
|
||||
See \ref page_api
|
||||
See \ref page_api.
|
||||
|
||||
### More Documentation
|
||||
# More Documentation
|
||||
|
||||
See our [Wiki](https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/home) for
|
||||
More information on how to configure and use PipeWire.
|
||||
|
||||
### Resources
|
||||
# Resources
|
||||
|
||||
- [PipeWire and AGL](https://wiki.automotivelinux.org/_media/pipewire_agl_20181206.pdf)
|
||||
- [LAC 2020 Paper](https://lac2020.sciencesconf.org/307881/document)
|
||||
|
@ -39,4 +40,5 @@ More information on how to configure and use PipeWire.
|
|||
- [PipeWire: The Linux audio/video bus (LWN)](https://lwn.net/Articles/847412)
|
||||
- [PipeWire Wikipedia](https://en.wikipedia.org/wiki/PipeWire)
|
||||
- [Bluetooth, PipeWire and Whatsapp calls](https://gjhenrique.com/pipewire.html)
|
||||
|
||||
*/
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/** \page page_overview Overview
|
||||
|
||||
PipeWire is a new low-level multimedia framework designed from scratch that
|
||||
aims to provide
|
||||
aims to provide:
|
||||
|
||||
- graph based processing
|
||||
- support for out-of-process processing graphs with minimal overhead
|
||||
- flexible and extensible media format negotiation and buffer allocation
|
||||
- Hard real-time capable plugins
|
||||
- achieve very low-latency for both audio and video processing
|
||||
- Graph based processing.
|
||||
- Support for out-of-process processing graphs with minimal overhead.
|
||||
- Flexible and extensible media format negotiation and buffer allocation.
|
||||
- Hard real-time capable plugins.
|
||||
- Achieve very low-latency for both audio and video processing.
|
||||
|
||||
The framework is used to build a modular daemon that can be configured to:
|
||||
|
||||
- be a low-latency audio server with features like pulseaudio and/or jack
|
||||
- a video capture server that can manage hardware video capture devices and
|
||||
provide access to them
|
||||
- a central hub where video can be made available for other applications
|
||||
- Be a low-latency audio server with features like PulseAudio and/or JACK.
|
||||
- A video capture server that can manage hardware video capture devices and
|
||||
provide access to them.
|
||||
- A central hub where video can be made available for other applications
|
||||
such as the gnome-shell screencast API.
|
||||
|
||||
|
||||
## Motivation
|
||||
# Motivation
|
||||
|
||||
Linux has no unified framework for exchanging multimedia content between
|
||||
applications or even devices. In most cases, developers realized that
|
||||
|
@ -29,14 +29,14 @@ a user-space daemon is needed to make this possible:
|
|||
- For video capture, we usually go directly to the hardware devices, with
|
||||
all security implications and inflexible routing that this brings.
|
||||
- For consumer audio, we use PulseAudio to manage and mix multiple streams
|
||||
from clients
|
||||
from clients.
|
||||
- For Pro audio, we use JACK to manage the graph of nodes.
|
||||
|
||||
None of these solutions (except perhaps to some extent Wayland), however,
|
||||
None of these solutions (except perhaps to some extent Wayland) however
|
||||
were designed to support the security features that are required when
|
||||
dealing with flatpaks or other containerized applications. PipeWire
|
||||
aims to solve this problem and provides a unified framework to run both
|
||||
consumer and Pro audio as well as video capture and processing in a
|
||||
consumer and pro audio as well as video capture and processing in a
|
||||
secure way.
|
||||
|
||||
*/
|
||||
|
|
|
@ -14,46 +14,47 @@ Permissions include `R` (read), `W` (write), `X` (execute) and `M` (metadata).
|
|||
Some of those methods will only query state, others will modify the object.
|
||||
As said above, modifying the object through one of these methods requires
|
||||
the `W` permission.
|
||||
- `M`: An object with M permission can be used as the subject in metadata.
|
||||
- `M`: An object with `M` permission can be used as the subject in metadata.
|
||||
|
||||
Clients with all permissions set are referred to as "ALL" in the
|
||||
documentation.
|
||||
|
||||
# Use cases
|
||||
|
||||
### New clients need their permissions configured
|
||||
# Use Cases
|
||||
|
||||
## New Clients Need Their Permissions Configured
|
||||
|
||||
A new client is not allowed to communicate with the PipeWire daemon until
|
||||
it has been configured with permissions.
|
||||
|
||||
### Flatpaks can't modify other stream/device volumes
|
||||
## Flatpaks Can't Modify Other Stream/Device Volumes
|
||||
|
||||
An application running as Flatpak should not be able to modify the state of
|
||||
certain objects. Permissions of the relevant PipeWire objects should not have
|
||||
the `W` permission to avoid this.
|
||||
|
||||
### Flatpaks can't move other streams to different devices
|
||||
## Flatpaks Can't Move Other Streams To Different Devices
|
||||
|
||||
Streams are moved to another device by setting the "target.node" metadata
|
||||
on the node id. By not setting the `M` bit on the other objects, this can be
|
||||
Streams are moved to another device by setting the `target.node` metadata
|
||||
on the node ID. By not setting the `M` bit on the other objects, this can be
|
||||
avoided.
|
||||
|
||||
### Application should be restricted in what they can see
|
||||
## Application Should Be Restricted In What They Can See
|
||||
|
||||
In general, applications should only be able to see the objects that they are
|
||||
allowed to see. For example, a web browser that was given access to a camera
|
||||
should not be able to see (and thus receive input data from) audio devices.
|
||||
|
||||
### "Manager" applications require full access
|
||||
## "Manager" Applications Require Full Access
|
||||
|
||||
Some applications require full access to the PipeWire graph, including
|
||||
moving streams between nodes (by setting metadata) and modifying properties
|
||||
(e.g. volume). These applications must work even when running as Flatpak.
|
||||
(eg. volume). These applications must work even when running as Flatpak.
|
||||
|
||||
|
||||
# Design
|
||||
|
||||
## The PipeWire daemon
|
||||
## The PipeWire Daemon
|
||||
|
||||
Immediately after a new client connects to the PipeWire daemon and updates
|
||||
its properties, the client will be registered and made visible to other
|
||||
|
@ -71,8 +72,7 @@ A suspended client can only resume processing after some other client
|
|||
sets the core permissions to `R`. This other client is usually a session
|
||||
manager, see e.g. \ref page_session_manager.
|
||||
|
||||
|
||||
## The PipeWire access module
|
||||
## The PipeWire Access Module
|
||||
|
||||
The \ref page_module_access hooks into the `check_access` event that is
|
||||
emitted when a new client is registered. The module checks the permissions of
|
||||
|
@ -80,23 +80,23 @@ the client and stores those in the \ref PW_KEY_ACCESS
|
|||
property on the client object. If this property is already set, the access
|
||||
module does nothing.
|
||||
|
||||
If the property is not set, it will go through a set of checks to determine
|
||||
the permissions for a client, see the \ref page_module_access documentation
|
||||
If the property is not set it will go through a set of checks to determine
|
||||
the permissions for a client. See the \ref page_module_access documentation
|
||||
for details, particularly on the values documented below. Depending on the
|
||||
value of the \ref PW_KEY_ACCESS property one the following happens:
|
||||
|
||||
- `"allowed"`, `"unrestricted"`: ALL permissions are set on the core
|
||||
object and the client will be able to resume.
|
||||
- `"restricted"`, `"flatpak"`, `"$access.force"`: no permissions are set on
|
||||
- `"restricted"`, `"flatpak"`, `"$access.force"`: No permissions are set on
|
||||
the core object and the client will be suspended.
|
||||
- `"rejected"`: an error is sent to the client and the client is
|
||||
- `"rejected"`: An error is sent to the client and the client is
|
||||
suspended.
|
||||
|
||||
As detailed above, the client may be suspended. In that case the session
|
||||
manager or another client is required to configure permissions on the object
|
||||
for it to resume.
|
||||
|
||||
## The session manager
|
||||
## The Session Manager
|
||||
|
||||
The session manager listens for new clients to appear. It will use the
|
||||
\ref PW_KEY_ACCESS property to determine what to do.
|
||||
|
@ -117,7 +117,7 @@ configure ALL permissions on the client. Possible checks include
|
|||
permission store checks or ask the user if the application is allowed
|
||||
full access.
|
||||
|
||||
Manager applications (i.e. applications that need to modify the graph) will
|
||||
Manager applications (ie. applications that need to modify the graph) will
|
||||
set the \ref PW_KEY_MEDIA_CATEGORY property in the client object to "Manager".
|
||||
|
||||
For details on the pipewire-media-session implementation of access control,
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
This document explains how Audio is implemented.
|
||||
|
||||
# Use cases
|
||||
# Use Cases
|
||||
|
||||
## Audio devices are made available as processing nodes/ports
|
||||
## Audio Devices Are Made Available As Processing Nodes/Ports
|
||||
|
||||
Applications need to be able to see a port for each stream of an
|
||||
Audio device.
|
||||
audio device.
|
||||
|
||||
### Audio devices can be plugged and unplugged
|
||||
## Audio Devices Can Be Plugged and Unplugged
|
||||
|
||||
When devices are plugged and unplugged the associated nodes/ports
|
||||
need to be created and removed.
|
||||
|
||||
### Audio port in canonical format
|
||||
## Audio Port In Canonical Format
|
||||
|
||||
It must be possible to make individual audio channels available
|
||||
as a single mono stream with a fixed format and samplerate.
|
||||
|
@ -22,7 +22,7 @@ as a single mono stream with a fixed format and samplerate.
|
|||
This makes it possible to link any of the audio ports together
|
||||
without doing conversions.
|
||||
|
||||
### Applications can connect to audio devices
|
||||
## Applications Can Connect To Audio Devices
|
||||
|
||||
Applications can create ports that can connect to the audio ports
|
||||
so that data can be provided to or consumed from them.
|
||||
|
@ -30,19 +30,19 @@ so that data can be provided to or consumed from them.
|
|||
It should be possible to automatically connect an application to
|
||||
a sink/source when it requests this.
|
||||
|
||||
### Default audio sink and sources
|
||||
## Default Audio Sink and Sources
|
||||
|
||||
It should be possible to mark a source or sink as the default source
|
||||
and sink so that applications are routed to them by default.
|
||||
|
||||
It should be possible to change the default audio sink/source.
|
||||
|
||||
### Application should be able to move between sinks/sources
|
||||
## Application Should Be Able To Move Between Sinks/Sources
|
||||
|
||||
It should be possible to move an application from one device to
|
||||
another dynamically.
|
||||
|
||||
### Exclusive access
|
||||
## Exclusive Access
|
||||
|
||||
Application should be able to connect to a device in exclusive mode.
|
||||
This allows the application to negotiate a specific format with the
|
||||
|
@ -62,13 +62,13 @@ Audio devices are implemented with an \ref spa_device "SPA Device" object.
|
|||
This object is then responsible for controlling the \ref spa_node "SPA Nodes" that
|
||||
provide the audio ports to interface with the device.
|
||||
|
||||
The Nodes operate on the native audio formats supported by the device.
|
||||
The nodes operate on the native audio formats supported by the device.
|
||||
This includes the sample rate as well as the number of channels and
|
||||
the audio format.
|
||||
|
||||
## Audio Adapter
|
||||
|
||||
An SPA Node called the "adapter" is usually used with the SPA device Node as
|
||||
An SPA Node called the "adapter" is usually used with the SPA device node as
|
||||
the internal node.
|
||||
|
||||
The function of the adapter is to convert the device native format to
|
||||
|
@ -80,14 +80,14 @@ as separate mono ports. This is called the DSP setup.
|
|||
|
||||
The audio adapter can also be configured in passthrough mode when it
|
||||
will not do any conversions but simply pass through the port information
|
||||
of the internal Node. This can be used to implement exclusive access.
|
||||
of the internal node. This can be used to implement exclusive access.
|
||||
|
||||
Setup of the different configurations of the adapter can be done with
|
||||
the PortConfig parameter.
|
||||
|
||||
## The session manager
|
||||
## The Session Manager
|
||||
|
||||
The session manager is responsible for creating Nodes and Ports for
|
||||
The session manager is responsible for creating nodes and ports for
|
||||
the various audio devices. It will need to wrap them into an audio
|
||||
adapter so that the specific configuration of the node can be
|
||||
decided by the policy mode.
|
||||
|
@ -96,33 +96,32 @@ The session manager should create name and description for the
|
|||
devices and nodes.
|
||||
|
||||
The session manager is responsible for assigning priorities to the
|
||||
Nodes. At least \ref PW_KEY_PRIORITY_SESSION and \ref PW_KEY_PRIORITY_DRIVER
|
||||
nodes. At least \ref PW_KEY_PRIORITY_SESSION and \ref PW_KEY_PRIORITY_DRIVER
|
||||
need to be set.
|
||||
|
||||
The session manager might need to work with other services to gain
|
||||
exclusive access to the device (e.g. DBus).
|
||||
exclusive access to the device (eg. DBus).
|
||||
|
||||
|
||||
# Implementation
|
||||
|
||||
## pipewire-media-session (alsa-monitor)
|
||||
## PipeWire Media Session (alsa-monitor)
|
||||
|
||||
PipeWire media session uses the \ref SPA_NAME_API_ALSA_ENUM_UDEV plugin
|
||||
for enumerating the ALSA devices. For each device it does:
|
||||
|
||||
- Try to acquire the DBus device reservation object to gain exclusive
|
||||
access to the device.
|
||||
- Create an SPA Device instance for the device and monitor this device instance.
|
||||
- For each Node created by the device, create an adapter with
|
||||
- Create an SPA device instance for the device and monitor this device instance.
|
||||
- For each node created by the device, create an adapter with
|
||||
an ALSA PCM node in the context of the PipeWire daemon.
|
||||
|
||||
The session manager will also create suitable names and descriptions
|
||||
for the Devices and Nodes that it creates as well as assign session
|
||||
for the devices and nodes that it creates as well as assign session
|
||||
and driver priorities.
|
||||
|
||||
The session manager has the option to add extra properties on the
|
||||
Devices and Node that it creates to control their behavior. This
|
||||
devices and nodes that it creates to control their behavior. This
|
||||
is implemented with match rules.
|
||||
|
||||
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,7 @@ Typically general, users run one PipeWire daemon that listens for incoming
|
|||
connections and manages devices. Clients (including the \ref
|
||||
page_session_manager) are separate processes that talk to the daemon using the
|
||||
PipeWire socket (default: `$XDG_RUNTIME_DIR/pipewire-0`). This approach
|
||||
provides provides address-space separation between the privileged daemon and
|
||||
provides address-space separation between the privileged daemon and
|
||||
non-privileged clients.
|
||||
|
||||
\dot
|
||||
|
@ -52,7 +52,7 @@ As shown above, the protocol is handled by the \ref
|
|||
page_module_protocol_native. From PipeWire's point-of-view this module is just
|
||||
another module.
|
||||
|
||||
\section sec_config Configuration Files
|
||||
# Configuration Files
|
||||
|
||||
On startup, the daemon reads a configuration file to configure itself.
|
||||
It executes a series of commands listed in the config file. The lookup order
|
||||
|
@ -75,14 +75,14 @@ They are applied to the global configuration file. Properties are overwritten
|
|||
and array elements are appended. This makes it possible to make small custom customizations
|
||||
or additions to the main configuration file.
|
||||
|
||||
The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX`
|
||||
and `PIPEWIRE_CONFIG_NAME` can be used to specify an alternative config
|
||||
directory, subdirectory and filename, respectively.
|
||||
The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX`,
|
||||
and `PIPEWIRE_CONFIG_NAME`. Can be used to specify an alternative configuration
|
||||
directory, subdirectory, and filename respectively.
|
||||
|
||||
\subsection sec_config_format Configuration File Format
|
||||
## Configuration File Format
|
||||
|
||||
PipeWire's configuration file format is JSON. In addition to true JSON,
|
||||
PipeWire also understands a more compact JSON representation where
|
||||
PipeWire's configuration file format is JSON. In addition to true JSON
|
||||
PipeWire also understands a more compact JSON representation. Where
|
||||
`"` can be omitted around strings, no trailing commas are required and
|
||||
`:` or `=` can be used to separate object keys from their values.
|
||||
Also, `#` can be used to start a comment until the end of the line.
|
||||
|
@ -117,63 +117,60 @@ Allowed configuration file sections are:
|
|||
|
||||
- **context.properties** (dictionary): These properties configure the
|
||||
pipewire instance.
|
||||
|
||||
- **context.spa-libs** (dictionary): Maps plugin features with globs to a
|
||||
spa library.
|
||||
|
||||
- **context.modules** (array): Each entry in the array is a dictionary with
|
||||
the name of the module to load, including optional args and flags. Most
|
||||
modules support being loaded multiple times.
|
||||
|
||||
- **context.objects** (array): Each entry in the array is a dictionary con‐
|
||||
taining the factory to create an object from and optional extra argu‐
|
||||
ments specific to that factory.
|
||||
|
||||
- **context.exec** (array): Each entry in the array is dictionary containing
|
||||
the path of a program to execute on startup and optional args. This ar‐
|
||||
ray usually contains an entry to start the session manager.
|
||||
|
||||
|
||||
\section sec_logging Logging
|
||||
# Logging
|
||||
|
||||
The `PIPEWIRE_DEBUG` environment variable can be used to enable
|
||||
more debugging. This variable supports one of two formats:
|
||||
|
||||
- `PIPEWIRE_DEBUG=<level>` where `<level>` is either a numerical log level or it's
|
||||
- `PIPEWIRE_DEBUG=<level>` where `<level>` is either a numerical log level or its
|
||||
respective key, see below.
|
||||
- `PIPEWIRE_DEBUG=<glob1>:<level1>,<glob2>:<level2>,...` where the globs are
|
||||
shell-globs to match on log topics and the levels are the respective
|
||||
log level to set for that topic. Globs are applied in-order and a matching
|
||||
shell globs to match on log topics and the levels are the respective
|
||||
log level to set for that topic. Globs are applied in order and a matching
|
||||
glob overrides an earlier glob for that category. For example,
|
||||
`PIPEWIRE_DEBUG=*:E,mod.*:D,mod.foo:X" enables global error messages,
|
||||
`PIPEWIRE_DEBUG=*:E,mod.*:D,mod.foo:X` enables global error messages,
|
||||
debugging on all modules but no messages on the foo module.
|
||||
|
||||
- `<level>` specifies the log level:
|
||||
+ `X` or `0`: no logging is enabled
|
||||
+ `E` or `1`: Error logging is enabled
|
||||
+ `W` or `2`: Warnings are enabled
|
||||
+ `I` or `3`: Informational messages are enabled
|
||||
+ `D` or `4`: Debug messages are enabled
|
||||
|
||||
+ `X` or `0`: No logging is enabled.
|
||||
+ `E` or `1`: Error logging is enabled.
|
||||
+ `W` or `2`: Warnings are enabled.
|
||||
+ `I` or `3`: Informational messages are enabled.
|
||||
+ `D` or `4`: Debug messages are enabled.
|
||||
+ `T` or `5`: Trace messages are enabled. These messages can be logged
|
||||
from the realtime threads.
|
||||
|
||||
PipeWire uses a "category.topic" naming scheme, with the following categories:
|
||||
- `pw.*`: pipewire-internal topics
|
||||
- `mod.*`: module topics, for example `mod.foo` would usually refer to the
|
||||
"foo" module
|
||||
- `ms.*`: media session topics
|
||||
- `ms.mod.*`: media session modules, for example `ms.foo` would usually refer
|
||||
to the "media-session-foo" module
|
||||
- `conn.*`: connection-specific topics such as printing raw messages sent over
|
||||
PipeWire uses a `category.topic` naming scheme, with the following categories:
|
||||
|
||||
- `pw.*`: PipeWire internal topics.
|
||||
- `mod.*`: Module topics, for example `mod.foo` would usually refer to the
|
||||
`foo` module.
|
||||
- `ms.*`: Media session topics.
|
||||
- `ms.mod.*`: Media session modules, for example `ms.foo` would usually refer
|
||||
to the `media-session-foo` module.
|
||||
- `conn.*`: Connection specific topics such as printing raw messages sent over
|
||||
a communication socket. These are in a separate namespace as they are
|
||||
usually vastly more verbose than the normal debugging topics.
|
||||
This namespace must be explicitly enabled with a `conn.<glob>` glob.
|
||||
|
||||
|
||||
The behavior of the logging can be further controlled with the following
|
||||
environment variables:
|
||||
- `PIPEWIRE_LOG_SYSTEMD=false`: disable logging to the systemd journal
|
||||
- `PIPEWIRE_LOG=<filename>`: redirect the log to the given filename
|
||||
- `PIPEWIRE_LOG_LINE=false`: don't log filename, function, and source code line
|
||||
|
||||
- `PIPEWIRE_LOG_SYSTEMD=false`: Disable logging to the systemd journal.
|
||||
- `PIPEWIRE_LOG=<filename>`: Redirect the log to the given filename.
|
||||
- `PIPEWIRE_LOG_LINE=false`: Don't log filename, function, and source code line.
|
||||
|
||||
*/
|
||||
|
|
|
@ -6,13 +6,13 @@ PipeWire is a media server that can run graphs of multimedia nodes.
|
|||
Nodes can run inside the server process or in separate processes,
|
||||
communicating with the server.
|
||||
|
||||
PipeWire was designed to
|
||||
PipeWire was designed to:
|
||||
|
||||
- be efficient for raw video using fd passing and audio with
|
||||
shared ringbuffers
|
||||
- be able to provide/consume/process media from any process
|
||||
- provide policy to restrict access to devices and streams
|
||||
- be easily extensible
|
||||
- Be efficient for raw video using fd passing and audio with
|
||||
shared ringbuffers.
|
||||
- Be able to provide/consume/process media from any process.
|
||||
- Provide policy to restrict access to devices and streams.
|
||||
- Be easily extensible.
|
||||
|
||||
Although an initial goal, the design is not limited to raw video
|
||||
only and should be able to handle compressed video and other
|
||||
|
@ -23,36 +23,30 @@ SPA is designed for low-latency and efficient processing of any multimedia
|
|||
format. SPA also provides a number of helper utilities that are not available
|
||||
in the standard C library.
|
||||
|
||||
Some of the application we intend to build
|
||||
Some of the application we intend to build:
|
||||
|
||||
- v4l2 device provider: Provide controlled access to v4l2 devices
|
||||
and share one device between multiple processes.
|
||||
|
||||
- gnome-shell video provider: GNOME Shell provides a node that
|
||||
gives the contents of the frame buffer for screen sharing or
|
||||
screen recording.
|
||||
|
||||
- audio server: Mix and playback multiple audio streams. The design
|
||||
is more like CRAS (Chromium audio server) than PulseAudio and with
|
||||
the added benefit that processing can be arranged in a graph.
|
||||
|
||||
- Pro audio graph processing like JACK.
|
||||
|
||||
- Media playback backend
|
||||
- v4l2 device provider: Provide controlled access to v4l2 devices
|
||||
and share one device between multiple processes.
|
||||
- gnome-shell video provider: GNOME Shell provides a node that
|
||||
gives the contents of the frame buffer for screen sharing or
|
||||
screen recording.
|
||||
- Audio server: Mix and playback multiple audio streams. The design
|
||||
is more like CRAS (Chromium audio server) than PulseAudio and with
|
||||
the added benefit that processing can be arranged in a graph.
|
||||
- Professional audio graph processing like JACK.
|
||||
- Media playback backend.
|
||||
|
||||
|
||||
Protocol
|
||||
--------
|
||||
# Protocol
|
||||
|
||||
The native protocol and object model is similar to
|
||||
[Wayland](https://wayland.freedesktop.org) but with custom
|
||||
serialization/deserialization of messages. This is because the datastructures
|
||||
serialization/deserialization of messages. This is because the data structures
|
||||
in the messages are more complicated and not easily expressible in XML.
|
||||
See \ref page_module_protocol_native for details.
|
||||
|
||||
|
||||
Extensibility
|
||||
-------------
|
||||
# Extensibility
|
||||
|
||||
The functionality of the server is implemented and extended with modules and
|
||||
extensions. Modules are server side bits of logic that hook into various
|
||||
|
@ -64,16 +58,13 @@ Extensions are the client side version of the modules. Most extensions provide
|
|||
both a client side and server side init function. New interfaces or new object
|
||||
implementation can easily be added with modules/extensions.
|
||||
|
||||
Some of the extensions that can be written
|
||||
Some of the extensions that can be written:
|
||||
|
||||
- protocol extensions: a client/server side API (.h) together with protocol
|
||||
extensions and server/client side logic to implement a new object or
|
||||
interface.
|
||||
|
||||
- a module to check security of method calls
|
||||
|
||||
- a module to automatically create, link or relink nodes
|
||||
|
||||
- a module to suspend idle nodes
|
||||
- Protocol extensions: A client/server side API (.h) together with protocol
|
||||
extensions and server/client side logic to implement a new object or
|
||||
interface.
|
||||
- A module to check security of method calls.
|
||||
- A module to automatically create, link or relink nodes.
|
||||
- A module to suspend idle nodes.
|
||||
|
||||
*/
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
/** \page page_library PipeWire Library
|
||||
|
||||
There are 2 main components that make up the PipeWire library:
|
||||
There are two main components that make up the PipeWire library:
|
||||
|
||||
1. An implementation of a graph based media processing engine.
|
||||
2. An asynchronous IPC mechanism to manipulate and introspect
|
||||
a graph in another process.
|
||||
a graph in another process.
|
||||
|
||||
There is usually a daemon that implements the global graph and
|
||||
clients that operate on this graph.
|
||||
|
||||
The IPC mechanism in PipeWire is inspired by wayland in that it
|
||||
The IPC mechanism in PipeWire is inspired by Wayland in that it
|
||||
follows the same design principles of objects and methods/events
|
||||
along with how this API is presented to the user.
|
||||
|
||||
|
@ -18,7 +18,8 @@ be added (or removed) by the user. Plugins can hook into many
|
|||
aspects of PipeWire and change the behaviour or number of
|
||||
features dynamically.
|
||||
|
||||
## Principles
|
||||
|
||||
# Principles
|
||||
|
||||
The PipeWire API is an object oriented asynchronous protocol.
|
||||
All requests and replies are method invocations on some object.
|
||||
|
@ -51,7 +52,8 @@ their state.
|
|||
State about objects can be obtained by binding to them and listening
|
||||
for state changes.
|
||||
|
||||
## Versioning
|
||||
|
||||
# Versioning
|
||||
|
||||
All interfaces have a version number. The maximum supported version
|
||||
number of an interface is advertized in the registry global event.
|
||||
|
@ -64,7 +66,8 @@ Interfaces increase their version number when new methods or events
|
|||
are added. Methods or events should never be removed or changed for
|
||||
simplicity.
|
||||
|
||||
## Proxies and resources
|
||||
|
||||
# Proxies and Resources
|
||||
|
||||
When a client connects to a PipeWire daemon, a new `struct pw_proxy`
|
||||
object is created with ID 0. The `struct pw_core` interface is
|
||||
|
@ -83,25 +86,22 @@ ID) becomes unused. The client is responsible for destroying the
|
|||
proxy when it no longer wants to use it.
|
||||
|
||||
|
||||
## Interfaces
|
||||
# Interfaces
|
||||
|
||||
### `struct pw_loop`
|
||||
## struct pw_loop
|
||||
|
||||
An abstraction for a `poll(2)` loop. It is usually part of one of:
|
||||
|
||||
* `struct pw_main_loop`: a helper that can run and stop a `pw_loop`.
|
||||
- `struct pw_main_loop`: A helper that can run and stop a `pw_loop`.
|
||||
- `struct pw_thread_loop`: A helper that can run and stop a `pw_loop`
|
||||
in a different thread. It also has some helper
|
||||
functions for various thread related synchronization
|
||||
issues.
|
||||
- `struct pw_data_loop`: A helper that can run and stop a `pw_loop`
|
||||
in a real-time thread along with some useful helper
|
||||
functions.
|
||||
|
||||
* `struct pw_thread_loop`: a helper that can run and stop a `pw_loop`
|
||||
in a different thread. It also has some helper
|
||||
functions for various thread related synchronization
|
||||
issues.
|
||||
|
||||
* `struct pw_data_loop`: a helper that can run and stop a `pw_loop`
|
||||
in a real-time thread along with some useful helper
|
||||
functions.
|
||||
|
||||
|
||||
### `struct pw_context`
|
||||
## struct pw_context
|
||||
|
||||
The main context for PipeWire resources. It keeps track of the mainloop,
|
||||
loaded modules, the processing graph and proxies to remote PipeWire
|
||||
|
@ -113,8 +113,7 @@ when creating a context.
|
|||
The context has methods to create the various objects you can use to
|
||||
build a server or client application.
|
||||
|
||||
|
||||
### `struct pw_core`
|
||||
## struct pw_core
|
||||
|
||||
A proxy to a remote PipeWire instance. This is used to send messages
|
||||
to a remote PipeWire daemon and to receive events from it.
|
||||
|
@ -125,63 +124,63 @@ or to perform a roundtrip message to flush out pending requests.
|
|||
Other core methods and events are used internally for the object
|
||||
life cycle management.
|
||||
|
||||
### `struct pw_registry`
|
||||
## struct pw_registry
|
||||
|
||||
A proxy to a PipeWire registry object. It emits events about the
|
||||
available objects on the server and can be used to bind to those
|
||||
objects in order to call methods or receive events from them.
|
||||
|
||||
### `struct pw_module`
|
||||
## struct pw_module
|
||||
|
||||
A proxy to a loadable module. Modules implement functionality such
|
||||
as provide new objects or policy.
|
||||
|
||||
### `struct pw_factory`
|
||||
## struct pw_factory
|
||||
|
||||
A proxy to an object that can create other objects.
|
||||
|
||||
### `struct pw_device`
|
||||
## struct pw_device
|
||||
|
||||
A proxy to a device object. Device objects model a physical hardware
|
||||
or software device in the system and can create other objects
|
||||
such as nodes or other devices.
|
||||
|
||||
### `struct pw_node`
|
||||
## struct pw_node
|
||||
|
||||
A Proxy to a processing node in the graph. Nodes can have input and
|
||||
output ports and the ports can be linked together to form a graph.
|
||||
|
||||
### `struct pw_port`
|
||||
## struct pw_port
|
||||
|
||||
A Proxy to an input or output port of a node. They can be linked
|
||||
A Proxy to an input or output port of a node. They can be linked
|
||||
together to form a processing graph.
|
||||
|
||||
### `struct pw_link`
|
||||
## struct pw_link
|
||||
|
||||
A proxy to a link between in output and input port. A link negotiates
|
||||
a format and buffers between ports. A port can be linked to many other
|
||||
ports and PipeWire will manage mixing and duplicating the buffers.
|
||||
|
||||
|
||||
## High level helper objects
|
||||
# High Level Helper Objects
|
||||
|
||||
Some high level objects are implemented to make it easier to interface
|
||||
with a PipeWire graph.
|
||||
|
||||
### `struct pw_filter`
|
||||
## struct pw_filter
|
||||
|
||||
A `struct pw_filter` allows you implement a processing filter that can
|
||||
be added to a PipeWire graph. It is comparable to a JACK client.
|
||||
|
||||
### `struct pw_stream`
|
||||
## struct pw_stream
|
||||
|
||||
a `struct pw_stream` makes it easy to implement a playback or capture
|
||||
A `struct pw_stream` makes it easy to implement a playback or capture
|
||||
client for the graph. It takes care of format conversion and buffer
|
||||
sizes. It is comparable to Core Audio AudioQueue or a PulseAudio
|
||||
stream.
|
||||
|
||||
|
||||
## Security
|
||||
# Security
|
||||
|
||||
With the default native protocol, clients connect to PipeWire using
|
||||
a named socket. This results in a client socket that is used to
|
||||
|
@ -215,13 +214,14 @@ PipeWire uses memfd (`memfd_create(2)`) or DMA-BUF for sharing media
|
|||
and data between clients. Clients can thus not look at other clients
|
||||
data unless they can see the objects and connect to them.
|
||||
|
||||
## Implementation
|
||||
|
||||
# Implementation
|
||||
|
||||
PipeWire also exposes an API to implement the server side objects in
|
||||
a graph.
|
||||
|
||||
|
||||
## Error reporting
|
||||
# Error Reporting
|
||||
|
||||
Functions return either NULL with errno set or a negative int error
|
||||
code when an error occurs. Error codes are used from the SPA plugin
|
||||
|
@ -237,6 +237,4 @@ signal the completion of the async operation (with, for example, a
|
|||
callback). The sequence number can be used to see which operation
|
||||
completed.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,41 +2,43 @@
|
|||
|
||||
This document explains how MIDI is implemented.
|
||||
|
||||
# Use cases
|
||||
|
||||
### MIDI devices are made available as processing nodes/ports
|
||||
# Use Cases
|
||||
|
||||
## MIDI Devices Are Made Available As Processing Nodes/Ports
|
||||
|
||||
Applications need to be able to see a port for each stream of a
|
||||
MIDI device.
|
||||
|
||||
### MIDI devices can be plugged and unplugged
|
||||
## MIDI Devices Can Be Plugged and Unplugged
|
||||
|
||||
When devices are plugged and unplugged the associated nodes/ports
|
||||
need to be created and removed.
|
||||
|
||||
### Applications can connect to MIDI devices
|
||||
## Applications Can Connect To MIDI Devices
|
||||
|
||||
Applications can create ports that can connect to the MIDI ports
|
||||
so that data can be provided to or consumed from them.
|
||||
|
||||
### Some MIDI devices are sinks or sources for midi data
|
||||
## Some MIDI Devices Are Sinks Or Sources For MIDI Data
|
||||
|
||||
It should be possible to create a MIDI sink or source that routes the
|
||||
midi events to specific midi ports.
|
||||
MIDI events to specific MIDI ports.
|
||||
|
||||
One example of such a sink would be in front of a software midi
|
||||
One example of such a sink would be in front of a software MIDI
|
||||
renderer.
|
||||
|
||||
An example of a MIDI source would be after a virtual keyboard or
|
||||
as a mix from many midi input devices.
|
||||
as a mix from many MIDI input devices.
|
||||
|
||||
### Applications should autoconnect to MIDI sinks or sources
|
||||
## Applications Should Auto-connect To MIDI Sinks Or Sources
|
||||
|
||||
An application should be able to be connected to a MIDI sink when
|
||||
it wants to play midi data.
|
||||
it wants to play MIDI data.
|
||||
|
||||
An application should be able to connect to a MIDI source when it
|
||||
wants to capture midi data.
|
||||
wants to capture MIDI data.
|
||||
|
||||
|
||||
# Design
|
||||
|
||||
|
@ -48,7 +50,7 @@ control input and output Ports. These ports have a media type of
|
|||
are of type \ref spa_pod_sequence with the \ref spa_pod_control type set to
|
||||
\ref SPA_CONTROL_Midi.
|
||||
|
||||
This means that every midi event is timestamped with the sample
|
||||
This means that every MIDI event is timestamped with the sample
|
||||
offset against the current graph clock cycle to get sample accurate
|
||||
midi events that can be aligned with the corresponding sample data.
|
||||
|
||||
|
@ -56,13 +58,13 @@ Since the MIDI events are embedded in the generic control stream,
|
|||
they can be interleaved with other control message types, such as
|
||||
property updates or OSC messages.
|
||||
|
||||
## The PipeWire daemon
|
||||
## The PipeWire Daemon
|
||||
|
||||
Nothing special is implemented for MIDI. Negotiation of formats
|
||||
happens between `"application/control"` media types and buffers are
|
||||
negotiated in the same way as any generic format.
|
||||
|
||||
## The session manager
|
||||
## The Session Manager
|
||||
|
||||
The session manager needs to create the MIDI nodes/ports for the available
|
||||
devices.
|
||||
|
@ -76,10 +78,10 @@ in order to route MIDI streams to them from applications that want this.
|
|||
|
||||
# Implementation
|
||||
|
||||
## pipewire-media-session
|
||||
## PipeWire Media Session
|
||||
|
||||
PipeWire media session uses the \ref SPA_NAME_API_ALSA_SEQ_BRIDGE plugin for
|
||||
the midi features. This creates a single SPA Node with ports per
|
||||
the MIDI features. This creates a single SPA Node with ports per
|
||||
MIDI client/stream.
|
||||
|
||||
The media session will check the permissions on `/dev/snd/seq` before
|
||||
|
@ -88,7 +90,7 @@ until the sequencer device node is accessible.
|
|||
|
||||
## JACK
|
||||
|
||||
JACK assumes all `"application/control"` ports are midi ports.
|
||||
JACK assumes all `"application/control"` ports are MIDI ports.
|
||||
|
||||
The control messages are converted to the JACK event format by
|
||||
filtering out the \ref SPA_CONTROL_Midi types. On output ports, the JACK
|
||||
|
@ -98,5 +100,4 @@ There is a 1 to 1 mapping between the JACK events and control
|
|||
messages so there is no information loss or need for complicated
|
||||
conversions.
|
||||
|
||||
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/**
|
||||
|
||||
\page page_pipewire_modules PipeWire Modules
|
||||
/** \page page_pipewire_modules PipeWire Modules
|
||||
|
||||
A PipeWire module is effectively a PipeWire client in an `.so` file that
|
||||
shares the \ref pw_context with the loading entity. Usually modules are
|
||||
|
@ -28,7 +26,7 @@ context.modules = [
|
|||
...
|
||||
]
|
||||
```
|
||||
And the matching libraries are:
|
||||
The matching libraries are:
|
||||
```
|
||||
$ ls -1 /usr/lib64/pipewire-0.3/libpipewire-module*
|
||||
...
|
||||
|
@ -49,7 +47,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args).`
|
|||
See the \ref page_module_example_sink and \ref page_module_example_source
|
||||
modules for a general oveview of how modules look like.
|
||||
|
||||
|
||||
List of known modules:
|
||||
|
||||
- \subpage page_module_access
|
||||
|
@ -79,5 +76,4 @@ List of known modules:
|
|||
- \subpage page_module_x11_bell
|
||||
- \subpage page_module_zeroconf_discover
|
||||
|
||||
|
||||
*/
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/** \page page_objects_design Objects Design
|
||||
|
||||
This document is a design reference on the various objects that exist
|
||||
in the PipeWire media and session management graphs, explaining what these
|
||||
objects are, how they are meant to be used and how they relate to other
|
||||
in the PipeWire media and session management graphs. Explaining what these
|
||||
objects are, how they are meant to be used, and how they relate to other
|
||||
kinds of objects and concepts that exist in subsystems or other libraries.
|
||||
|
||||
## The media graph
|
||||
|
||||
# The Media Graph
|
||||
|
||||
The media graph represents and enables the media flow inside the PipeWire
|
||||
daemon and between the daemon and its clients. It consists of nodes, ports
|
||||
|
@ -21,7 +22,7 @@ and links.
|
|||
+------------+ +------------+
|
||||
```
|
||||
|
||||
### Node
|
||||
## Node
|
||||
|
||||
A **node** is a media processing element. It consumes and/or produces buffers
|
||||
that contain data, such as audio or video.
|
||||
|
@ -33,26 +34,28 @@ client using the PipeWire protocol.
|
|||
In an analogy to GStreamer, a _node_ is similar (but not equal) to a
|
||||
GStreamer _element_.
|
||||
|
||||
### Port
|
||||
## Port
|
||||
|
||||
A **port** is attached on a **node** and provides an interface for input
|
||||
or output of media on the node. A node may have multiple ports.
|
||||
|
||||
A port always has a direction, input or output:
|
||||
|
||||
- Input: it allows media input into the node (in other terms, it is a _sink_)
|
||||
- Output: it outputs media out of the node (in other terms, it is a _source_)
|
||||
|
||||
In an analogy to GStreamer, a _port_ is similar (but not equal) to a
|
||||
GStreamer _pad_.
|
||||
|
||||
### Link
|
||||
## Link
|
||||
|
||||
A **link** connects 2 ports of opposite direction, making media flow from
|
||||
A **link** connects two ports of opposite direction, making media flow from
|
||||
the output port to the input port.
|
||||
|
||||
## The session management graph
|
||||
|
||||
The session management graph is a virtual, higher-level representation of the
|
||||
# The Session Management Graph
|
||||
|
||||
The session management graph is a virtual, higher level representation of the
|
||||
media flow. It is created entirely by the session manager and it can affect
|
||||
the routing on the media graph only through the session manager's actions.
|
||||
|
||||
|
@ -70,28 +73,31 @@ codebase.
|
|||
+---------------------+ +----------------------+
|
||||
```
|
||||
|
||||
### Endpoint
|
||||
## Endpoint
|
||||
|
||||
An **endpoint** is a session management object that provides a representation
|
||||
of user-conceivable places where media can be routed to/from.
|
||||
of user conceivable places where media can be routed to/from.
|
||||
|
||||
Examples of endpoints associated with hardware on a desktop-like system:
|
||||
- Laptop speakers
|
||||
- USB webcam
|
||||
- Bluetooth headset microphone
|
||||
- Line out stereo jack port
|
||||
|
||||
- Laptop speakers.
|
||||
- USB webcam.
|
||||
- Bluetooth headset microphone.
|
||||
- Line out stereo jack port.
|
||||
|
||||
Examples of endpoints associated with hardware in a car:
|
||||
- Speakers amplifier
|
||||
- Front right seat microphone array
|
||||
- Rear left seat headphones
|
||||
- Bluetooth phone voice gateway
|
||||
- Hardware FM radio device
|
||||
|
||||
- Speakers amplifier.
|
||||
- Front right seat microphone array.
|
||||
- Rear left seat headphones.
|
||||
- Bluetooth phone voice gateway.
|
||||
- Hardware FM radio device.
|
||||
|
||||
Examples of endpoints associated with software:
|
||||
- Desktop screen capture source
|
||||
- Media player application
|
||||
- Camera application
|
||||
|
||||
- Desktop screen capture source.
|
||||
- Media player application.
|
||||
- Camera application.
|
||||
|
||||
In most cases an endpoint maps to a node on the media graph, but this is not
|
||||
always the case. An endpoint may be backed by several nodes or no nodes at all.
|
||||
|
@ -107,7 +113,7 @@ be able to represent the *CD player endpoint* and the _endpoint link_ between
|
|||
it and the amplifier, so that it can apply audio policy that takes into account
|
||||
whether the CD player is playing or not.
|
||||
|
||||
#### Target
|
||||
### Target
|
||||
|
||||
An **endpoint** may be grouping together targets that can be reached by
|
||||
following the same route and they are mutually exclusive with each other.
|
||||
|
@ -121,7 +127,7 @@ In this case, a session manager may choose to group these two targets into the
|
|||
same endpoint, using a parameter on the _endpoint_ object to allow the user
|
||||
to choose the target (if the hardware allows configuring this at all).
|
||||
|
||||
### Endpoint Stream
|
||||
## Endpoint Stream
|
||||
|
||||
An **endpoint stream** is attached to an **endpoint** and represents a logical
|
||||
path that can be taken to reach this endpoint, often associated with
|
||||
|
@ -129,45 +135,48 @@ a _use case_.
|
|||
|
||||
For example, the "Speakers amplifier" endpoint in a car might have the
|
||||
following streams:
|
||||
- _Music_: a path to play music;
|
||||
the implementation will output this to all speakers, using the volume
|
||||
that has been configured for the "Music" use case
|
||||
- _Voice_: a path to play a voice message, such as a navigation message or
|
||||
feedback from a voice assistant; the implementation will output this
|
||||
to the front speakers only, lowering the volume of the music (if any)
|
||||
on these speakers at the same time
|
||||
- _Emergency_: a path to play an emergency situation sound (a beep,
|
||||
or equivalent); the implementation will output this on all speakers,
|
||||
increasing the volume to a factory-defined value if necessary (to ensure
|
||||
that it is audible) while muting audio from all other streams at the
|
||||
same time
|
||||
|
||||
- _Music_: A path to play music;
|
||||
the implementation will output this to all speakers, using the volume
|
||||
that has been configured for the "Music" use case.
|
||||
- _Voice_: A path to play a voice message; such as a navigation message or
|
||||
feedback from a voice assistant, the implementation will output this
|
||||
to the front speakers only. Lowering the volume of the music (if any)
|
||||
on these speakers at the same time.
|
||||
- _Emergency_: A path to play an emergency situation sound (a beep,
|
||||
or equivalent); the implementation will output this on all speakers.
|
||||
Increasing the volume to a factory defined value if necessary (to ensure
|
||||
that it is audible) while muting audio from all other streams at the
|
||||
same time.
|
||||
|
||||
In another example, a microphone that can be used for activating a voice
|
||||
assistant might have the following streams:
|
||||
- _Capture_: a path to capture directly from the microphone; this can be used
|
||||
by an application that listens for the assistant's wake-word in order
|
||||
to activate the full voice recognition engine
|
||||
- _CaptureDelayed_: a path to capture with a constant delay (meaning that
|
||||
starting capturing now will actually capture something that was spoken
|
||||
a little earlier); this can be used by the full voice recognition engine,
|
||||
allowing it to start after the wake-word has been spoken while capturing
|
||||
audio that also includes the wake-word
|
||||
|
||||
- _Capture_: A path to capture directly from the microphone; this can be used
|
||||
by an application that listens for the assistant's wake-word in order
|
||||
to activate the full voice recognition engine.
|
||||
- _CaptureDelayed_: A path to capture with a constant delay (meaning that
|
||||
starting capturing now will actually capture something that was spoken
|
||||
a little earlier); this can be used by the full voice recognition engine,
|
||||
allowing it to start after the wake-word has been spoken while capturing
|
||||
audio that also includes the wake-word.
|
||||
|
||||
Endpoint streams may be mutually exclusive or they may used simultaneously,
|
||||
depending on the implementation.
|
||||
|
||||
Endpoint streams may be implemented in many ways:
|
||||
- By plugging additional nodes in the media graph that link to the device node
|
||||
(ex. a simple buffering node linked to an alsa source node could implement
|
||||
the _CaptureDelayed_ stream in the above microphone example)
|
||||
- By using a different device node (ex. different ALSA device on the same card)
|
||||
that has a special meaning for the hardware
|
||||
- By triggering switches on the hardware (ex. modify ALSA controls on the
|
||||
same device)
|
||||
|
||||
### Endpoint Link
|
||||
- By plugging additional nodes in the media graph that link to the device node
|
||||
(ex. a simple buffering node linked to an alsa source node could implement
|
||||
the _CaptureDelayed_ stream in the above microphone example).
|
||||
- By using a different device node (ex. different ALSA device on the same card)
|
||||
that has a special meaning for the hardware.
|
||||
- By triggering switches on the hardware (ex. modify ALSA controls on the
|
||||
same device).
|
||||
|
||||
An **endpoint link** connects 2 streams from 2 different endpoints, creating
|
||||
## Endpoint Link
|
||||
|
||||
An **endpoint link** connects two streams from two different endpoints, creating
|
||||
a logical representation of media flow between the endpoints.
|
||||
|
||||
An **endpoint link** may be implemented by creating one or more _links_ in the
|
||||
|
@ -175,7 +184,7 @@ underlying media graph, or it may be implemented by configuring hardware
|
|||
resources to enable media flow, in case the flow does not pass through the
|
||||
media graph.
|
||||
|
||||
#### Constructing
|
||||
### Constructing
|
||||
|
||||
Constructing an **endpoint link** is done by asking the _endpoint stream_
|
||||
objects to prepare it. First, the source stream is asked to provide linking
|
||||
|
@ -185,40 +194,43 @@ When this is done, the session manager is asked to create the link using the
|
|||
provided information.
|
||||
|
||||
This mechanism allows stream implementations:
|
||||
- to prepare for linking, adjusting hardware paths if necessary
|
||||
- to check for stream linking compatibility; not all streams can be connected
|
||||
to all others (ex. streams with media flow in the hardware cannot be linked
|
||||
to streams that are backed by nodes in the media graph)
|
||||
- to provide implementation-specific information for linking; in the standard
|
||||
case this is going to be a list of _ports_ to be linked in the media graph,
|
||||
but in a hardware-flow case it can be any kind of hardware-specific detail
|
||||
|
||||
## Other related objects
|
||||
- To prepare for linking, adjusting hardware paths if necessary.
|
||||
- To check for stream linking compatibility; not all streams can be connected
|
||||
to all others (ex. streams with media flow in the hardware cannot be linked
|
||||
to streams that are backed by nodes in the media graph).
|
||||
- To provide implementation specific information for linking; in the standard
|
||||
case this is going to be a list of _ports_ to be linked in the media graph,
|
||||
but in a hardware-flow case it can be any kind of hardware-specific detail.
|
||||
|
||||
### Device
|
||||
|
||||
# Other Related Objects
|
||||
|
||||
## Device
|
||||
|
||||
A **device** represents a handle to an underlying API that is used to create
|
||||
higher level objects, such as nodes, or other devices.
|
||||
|
||||
Well-known devices include:
|
||||
|
||||
| Device API | Description |
|
||||
| :--- | :--- |
|
||||
| alsa.pcm.device | A handle to an ALSA card (ex. `hw:0`, `hw:1`, etc) |
|
||||
| alsa.seq.device | A handle to an ALSA Midi device |
|
||||
| v4l2.device | A handle to a V4L2 device (`/dev/video0`, `/dev/video1`, etc..) |
|
||||
| jack.device | A JACK client, allowing PipeWire to slave to JACK for audio input/output |
|
||||
| alsa.pcm.device | A handle to an ALSA card (ex. `hw:0`, `hw:1`, etc). |
|
||||
| alsa.seq.device | A handle to an ALSA Midi device. |
|
||||
| v4l2.device | A handle to a V4L2 device (`/dev/video0`, `/dev/video1`, etc..). |
|
||||
| jack.device | A JACK client, allowing PipeWire to slave to JACK for audio input/output. |
|
||||
|
||||
A device may have a _profile_, which allows the user to choose between
|
||||
multiple configurations that the device may be capable of having, or to simply
|
||||
turn the device _off_, which means that the handle is closed and not used
|
||||
by PipeWire.
|
||||
|
||||
### Session
|
||||
## Session
|
||||
|
||||
The **session** represents the session manager and can be used to expose
|
||||
global properties or methods that affect the session management.
|
||||
|
||||
#### Default endpoints
|
||||
### Default Endpoints
|
||||
|
||||
The session is responsible for book-keeping the default device endpoints (one
|
||||
for each kind of device) that is to be used to link new clients when
|
||||
|
@ -227,17 +239,18 @@ device preferences.
|
|||
|
||||
For example, a system may have both "Speakers" and "HDMI" endpoints on the
|
||||
"Audio Output" category and the user may be offered to make a choice within
|
||||
the UI to select which endpoint she wants to use by default for audio output.
|
||||
the UI to select which endpoint they want to use by default for audio output.
|
||||
This preference is meant to be stored in the session object.
|
||||
|
||||
#### Multiple sessions
|
||||
### Multiple Sessions
|
||||
|
||||
It is not currently defined whether it is allowed to have multiple sessions
|
||||
or not and how the system should behave if this happens.
|
||||
|
||||
## Mappings to underlying subsystem objects
|
||||
|
||||
### ALSA UCM
|
||||
# Mappings To Underlying Subsystem Objects
|
||||
|
||||
## ALSA UCM
|
||||
|
||||
This is a ***proposal***
|
||||
|
||||
|
@ -252,15 +265,15 @@ This is a ***proposal***
|
|||
In UCM mode, an ALSA card is represented as a PipeWire device, with the
|
||||
available UCM verbs listed as profiles of the device.
|
||||
|
||||
Activating a profile (i.e. a verb) will create the necessary nodes for the
|
||||
Activating a profile (ie. a verb) will create the necessary nodes for the
|
||||
available PCM streams and at the same time it will also create one endpoint
|
||||
for each UCM device. Optionally, conflicting UCM devices can be grouped in
|
||||
for each UCM device. Optionally conflicting UCM devices can be grouped in
|
||||
the same endpoint, listing the conflicting options as targets of the endpoint.
|
||||
|
||||
The available UCM modifiers for each UCM device will be added as streams, plus
|
||||
one "default" stream for accessing the device with no modifiers.
|
||||
|
||||
### ALSA fallback
|
||||
## ALSA Fallback
|
||||
|
||||
| ALSA | PipeWire |
|
||||
| :--- | :--- |
|
||||
|
@ -268,15 +281,15 @@ one "default" stream for accessing the device with no modifiers.
|
|||
| PCM stream | node + endpoint |
|
||||
|
||||
In the case where UCM (or another similar mechanism) is not available,
|
||||
ALSA cards are represented as PipeWire devices with only 2 profiles: On/Off
|
||||
ALSA cards are represented as PipeWire devices with only two profiles on/off.
|
||||
|
||||
When the On profile is activated, a node and an associated endpoint are created
|
||||
When the on profile is activated, a node and an associated endpoint are created
|
||||
for every available PCM stream.
|
||||
|
||||
Endpoints in this case have only one "default" stream, unless they are extended
|
||||
by the session manager to have software-backed streams.
|
||||
|
||||
### V4L2
|
||||
## V4L2
|
||||
|
||||
***FIXME***
|
||||
|
||||
|
@ -284,11 +297,12 @@ by the session manager to have software-backed streams.
|
|||
| :--- | :--- |
|
||||
| device | device + node |
|
||||
|
||||
## Relationship to other APIs
|
||||
|
||||
### PulseAudio
|
||||
# Relationship To Other API's
|
||||
|
||||
#### Mapping PipeWire objects for access by PulseAudio clients
|
||||
## PulseAudio
|
||||
|
||||
### Mapping PipeWire Objects For Access By PulseAudio Clients
|
||||
|
||||
| PipeWire | PulseAudio |
|
||||
| :--- | :--- |
|
||||
|
@ -297,21 +311,21 @@ by the session manager to have software-backed streams.
|
|||
| endpoint (associated with a device) | sink / source |
|
||||
| endpoint (associated with a client) | sink-input / source-output |
|
||||
| endpoint target | port |
|
||||
| endpoint stream | N/A, pa clients will be limited to the default stream |
|
||||
| endpoint stream | N/A, PA clients will be limited to the default stream |
|
||||
|
||||
#### Mapping PulseAudio clients to PipeWire
|
||||
### Mapping PulseAudio Clients To PipeWire
|
||||
|
||||
| PulseAudio | PipeWire |
|
||||
| :--- | :--- |
|
||||
| stream | client + node + endpoint (no targets, 1 default stream) |
|
||||
|
||||
### Jack
|
||||
## Jack
|
||||
|
||||
Note: This section is about JACK clients connecting to PipeWire through the
|
||||
JACK compatibility library. The scenario where PipeWire connects to another
|
||||
JACK server as a client is out of scope here.
|
||||
|
||||
#### Mapping PipeWire objects for access by JACK clients
|
||||
### Mapping PipeWire Objects For Access By JACK Clients
|
||||
|
||||
| PipeWire | JACK |
|
||||
| :--- | :--- |
|
||||
|
@ -320,7 +334,7 @@ JACK server as a client is out of scope here.
|
|||
| device | N/A |
|
||||
| endpoint | N/A |
|
||||
|
||||
#### Mapping JACK clients to PipeWire
|
||||
### Mapping JACK Clients To PipeWire
|
||||
|
||||
| JACK | PipeWire |
|
||||
| :--- | :--- |
|
||||
|
@ -328,6 +342,6 @@ JACK server as a client is out of scope here.
|
|||
| port | port |
|
||||
|
||||
JACK clients do not create endpoints. A session manager should be JACK aware
|
||||
in order to anticipate direct node linking
|
||||
in order to anticipate direct node linking.
|
||||
|
||||
*/
|
||||
|
|
|
@ -12,13 +12,14 @@ connects to PipeWire on behalf of the client, informing PipeWire that this
|
|||
client is a portal-managed client. PipeWire can detect and enforce
|
||||
extra permission checks on the portal managed clients.
|
||||
|
||||
Once such portal is the [Camera
|
||||
Once such portal is the [camera
|
||||
portal](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Camera)
|
||||
that provides a PipeWire session to stream video from a camera.
|
||||
|
||||
# Use cases
|
||||
|
||||
### new portal managed clients need device permissions configured
|
||||
# Use Cases
|
||||
|
||||
## New Portal Managed Clients Need Device Permissions Configured
|
||||
|
||||
When a new client is detected, the available objects need to be
|
||||
scanned and permissions configured for each of them.
|
||||
|
@ -26,7 +27,7 @@ scanned and permissions configured for each of them.
|
|||
Only the devices belonging to the media_roles given by the
|
||||
portal are considered.
|
||||
|
||||
### new devices need to be made visible to portal managed clients
|
||||
## New Devices Need To Be Made Visible To Portal Managed Clients
|
||||
|
||||
Newly created objects are made visible to a client when the client
|
||||
is allowed to interact with it.
|
||||
|
@ -34,7 +35,7 @@ is allowed to interact with it.
|
|||
Only the devices belonging to the media_roles given by the
|
||||
portal are considered.
|
||||
|
||||
### permissions for a device need to be revoked
|
||||
## Permissions For A Device Need To Be Revoked
|
||||
|
||||
The session manager listens to changes in the permissions of devices
|
||||
and will remove the client permissions accordingly.
|
||||
|
@ -46,7 +47,7 @@ where these permissions can be managed.
|
|||
|
||||
# Design
|
||||
|
||||
## The portal
|
||||
## The Portal
|
||||
|
||||
A sandboxed client cannot connect to PipeWire directly. Instead, it connects
|
||||
to the sandbox side of the portal which then connects the PipeWire daemon to
|
||||
|
@ -59,7 +60,7 @@ client object:
|
|||
|
||||
- `"pipewire.access.portal.is_portal" = true` for the connection of the
|
||||
portal itself (as opposed to a client managed by the portal).
|
||||
- `"pipewire.access.portal.app_id"` the [application id](https://docs.flatpak.org/en/latest/conventions.html#application-ids) of the client.
|
||||
- `"pipewire.access.portal.app_id"` the [application ID](https://docs.flatpak.org/en/latest/conventions.html#application-ids) of the client.
|
||||
- `"pipewire.access.portal.media_roles"` media roles of the client.
|
||||
Currently only `"Camera"` is defined.
|
||||
|
||||
|
@ -69,9 +70,9 @@ the task of the \ref page_session_manager to make the objects in the graph
|
|||
visible, depending on the client's `media_roles` (see also \ref
|
||||
PW_KEY_MEDIA_ROLE).
|
||||
|
||||
## The PipeWire portal module
|
||||
## The PipeWire Portal Module
|
||||
|
||||
The pipewire daemon uses the \ref page_module_portal to find the PID of the
|
||||
The PipeWire daemon uses the \ref page_module_portal to find the PID of the
|
||||
processes that owns the DBus name `org.freedesktop.portal.Desktop`
|
||||
(see the [XDG Desktop Portal](https://github.com/flatpak/xdg-desktop-portal)).
|
||||
|
||||
|
@ -99,7 +100,7 @@ digraph pw {
|
|||
}
|
||||
\enddot
|
||||
|
||||
## The client
|
||||
## The Client
|
||||
|
||||
A client can ask the portal for a connection to the PipeWire daemon.
|
||||
|
||||
|
@ -145,7 +146,6 @@ digraph pw {
|
|||
}
|
||||
\enddot
|
||||
|
||||
|
||||
The file descriptor for this restricted connection is passed back to the
|
||||
client which can now make use of the resources it has been permitted to
|
||||
access.
|
||||
|
@ -169,7 +169,7 @@ digraph pw {
|
|||
}
|
||||
\enddot
|
||||
|
||||
## The session manager
|
||||
## The Session Manager
|
||||
|
||||
The session manager listens for new clients to appear. It will use the
|
||||
\ref PW_KEY_ACCESS property to find portal connections. For client connections
|
||||
|
|
|
@ -6,38 +6,41 @@ applications to exchange data.
|
|||
It provides the mechanism to do so but the policy deciding which components
|
||||
can talk to each other and when is controlled by the session manager. As
|
||||
outlined in \ref page_objects_design, PipeWire provides a media graph
|
||||
consistent of Devices, Nodes and Ports. The session manager is the one that
|
||||
consisting of devices, nodes and ports. The session manager is the one that
|
||||
decides on the links between those elements.
|
||||
|
||||
Two prominent session managers currently exist:
|
||||
|
||||
- [PipeWire Media Session](https://gitlab.freedesktop.org/pipewire/media-session), the
|
||||
example session manager
|
||||
example session manager.
|
||||
- [WirePlumber](https://gitlab.freedesktop.org/pipewire/wireplumber), a
|
||||
modular session manager based on GObject
|
||||
modular session manager based on GObject.
|
||||
[Documentation](https://pipewire.pages.freedesktop.org/wireplumber/)
|
||||
|
||||
This page describes some of the requirements for session managers in general.
|
||||
|
||||
## Client management
|
||||
|
||||
# Client Management
|
||||
|
||||
PipeWire provides a \ref page_access "permission system" to limit client's
|
||||
access to resources but only \ref page_module_access "basic permission
|
||||
handling". The session manager is expected to decide whether clients may
|
||||
access specific resources.
|
||||
|
||||
## Device management
|
||||
|
||||
# Device Management
|
||||
|
||||
PipeWire's responsibility is to open devices, however the decision on which
|
||||
devices should be opened is the job of a session manager, including the
|
||||
configuration of those devices.
|
||||
|
||||
|
||||
## Endpoint grouping
|
||||
# Endpoint Grouping
|
||||
|
||||
An endpoint is, effectively, a group of Nodes that are a logical unit that can
|
||||
An endpoint is, effectively, a group of nodes that are a logical unit that can
|
||||
consume or produce media data. For example, a Bluetooth speaker may present as
|
||||
several Nodes but is only one logical unit to stream audio to.
|
||||
several nodes but is only one logical unit to stream audio to.
|
||||
|
||||
See \ref page_objects_design for details on Endpoints.
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/** \page page_pipewire PipeWire Design
|
||||
|
||||
## Internals
|
||||
# Internals
|
||||
|
||||
- \subpage page_design
|
||||
- \subpage page_audio
|
||||
|
@ -11,13 +11,15 @@
|
|||
- \subpage page_library
|
||||
- \subpage page_dma_buf
|
||||
|
||||
## Components
|
||||
|
||||
# Components
|
||||
|
||||
- \subpage page_daemon
|
||||
- \subpage page_tools
|
||||
- \subpage page_session_manager
|
||||
|
||||
## Backends
|
||||
|
||||
# Backends
|
||||
|
||||
- \subpage page_pulseaudio
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
/** \page page_pulseaudio PulseAudio compatibility
|
||||
/** \page page_pulseaudio PulseAudio Compatibility
|
||||
|
||||
# Internals - Mapping between ALSA and streams
|
||||
# Internals - Mapping Between ALSA and Streams
|
||||
|
||||
This explains the mapping between alsa cards and streams and session manager
|
||||
objects.
|
||||
|
||||
|
||||
## ALSA Cards
|
||||
|
||||
An ALSA card is exposed as a PipeWire device
|
||||
An ALSA card is exposed as a PipeWire device.
|
||||
|
||||
## Streams
|
||||
|
||||
Each alsa PCM is opened and a Node is created for each PCM stream.
|
||||
Each ALSA PCM is opened and a node is created for each PCM stream.
|
||||
|
||||
|
||||
# Session Manager
|
||||
|
||||
|
@ -22,8 +22,8 @@ The mapping of the PipeWire object hierarchy to the ALSA object hierarchy is the
|
|||
|
||||
One PipeWire device is created for every ALSA card.
|
||||
|
||||
For each UCM verb, a Node is created for the associated PCM devices.
|
||||
For each UCM verb, an Endpoint is created.
|
||||
- For each UCM verb, a node is created for the associated PCM devices.
|
||||
- For each UCM verb, an endpoint is created.
|
||||
|
||||
In a first step: For each available combination of UCM device and modifier,
|
||||
a stream is created. Streams are marked with compatible other streams.
|
||||
|
@ -31,26 +31,23 @@ a stream is created. Streams are marked with compatible other streams.
|
|||
Streams with the same modifier and mutually exclusive devices are grouped
|
||||
into one stream and the UCM devices are exposed on the endpoint as destinations.
|
||||
|
||||
|
||||
## ALSA fallback
|
||||
## ALSA Fallback
|
||||
|
||||
Each PCM stream (node) becomes an endpoint. The endpoint references the
|
||||
alsa device id
|
||||
ALSA device ID.
|
||||
|
||||
Each endpoint has 1 stream (for now) called HiFi Playback / HiFi Capture.
|
||||
Each endpoint has one stream (for now) called HiFi Playback / HiFi Capture.
|
||||
|
||||
More streams can be created depending on the format of the node.
|
||||
|
||||
## ALSA Pulse UCM
|
||||
|
||||
## ALSA pulse UCM
|
||||
Using the ALSA backend of PulseAudio we can create the following streams.
|
||||
|
||||
Using the alsa backend of pulseaudio we can create the following streams
|
||||
## ALSA Pulse Fallback
|
||||
|
||||
|
||||
## ALSA pulse fallback
|
||||
|
||||
The pulse alsa backend will use the mixer controls and some probing to
|
||||
create the following nodes and endpoints
|
||||
The pulse ALSA backend will use the mixer controls and some probing to
|
||||
create the following nodes and endpoints.
|
||||
|
||||
|
||||
# PulseAudio
|
||||
|
@ -58,14 +55,14 @@ create the following nodes and endpoints
|
|||
PulseAudio uses the session manager API to construct cards with profiles
|
||||
and sink/source with ports.
|
||||
|
||||
If an Endpoint references a Device, a card object is created for the device.
|
||||
If an endpoint references a device, a card object is created for the device.
|
||||
|
||||
Each Endpoint becomes a sink/source.
|
||||
Each endpoint becomes a sink/source.
|
||||
|
||||
Each Stream in the endpoint becomes a profile on the PulseAudio card. Because
|
||||
only one profile is selected on the device, only 1 stream is visible on
|
||||
only one profile is selected on the device, only one stream is visible on
|
||||
the endpoint. This clashes with the notion that multiple streams can be
|
||||
active at the same time but is a pulseaudio limitation.
|
||||
active at the same time but is a PulseAudio limitation.
|
||||
|
||||
Each Endpoint destination becomes a port on the sink/source.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ A \ref spa_buffer "SPA Buffer" contains metadata and data. There can be many met
|
|||
|
||||
> What is the `void*` data pointer in `spa_data`?
|
||||
|
||||
The data information either has a file descriptor or a data pointer. The type of the `spa_data` tells you what to expect. For a file descriptor, the data pointer can optionally be set when the fd is mapped into memory. Otherwise the user has to mmap the data herself.
|
||||
The data information either has a file descriptor or a data pointer. The type of the `spa_data` tells you what to expect. For a file descriptor, the data pointer can optionally be set when the FD is mapped into memory. Otherwise the user has to mmap the data themselves.
|
||||
|
||||
Also associated with each `spa_data` is a chunk, which is read/write and contains the valid region in the `spa_data` (offset, size, stride and some flags).
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
Types are generally divided into two categories:
|
||||
|
||||
- String types: They identify interfaces and highlevel object types.
|
||||
- integer types: These are enumerations used in the parts where high
|
||||
- Integer types: These are enumerations used in the parts where high
|
||||
performance/ease of use/low space overhead is needed.
|
||||
|
||||
The SPA type is system is statis and very simple but still allows you
|
||||
|
@ -15,7 +15,7 @@ to make and introspect complex object type hierarchies.
|
|||
|
||||
See the type system docs for more info.
|
||||
|
||||
## Error codes
|
||||
## Error Codes
|
||||
|
||||
SPA uses negative integers as errno style error codes. Functions that return an
|
||||
int result code generated an error when < 0. `spa_strerror()` can be used to
|
||||
|
@ -27,9 +27,9 @@ in the lower bits. This result is normally identified as a positive success
|
|||
result code and the sequence number can later be matched to the completion
|
||||
event.
|
||||
|
||||
## Useful macros
|
||||
## Useful Macros
|
||||
|
||||
SPA comes with some useful macros defined in `<spa/utils/defs.h>` and a
|
||||
number of utility functions, see \ref spa_utils
|
||||
number of utility functions, see \ref spa_utils.
|
||||
|
||||
*/
|
||||
|
|
|
@ -5,30 +5,34 @@ plugins.
|
|||
|
||||
It is inspired by many other plugin APIs, mostly LV2 and
|
||||
GStreamer. SPA provides two parts:
|
||||
- a header-only API with no external dependencies
|
||||
- a set of support libraries ("plugins") for commonly used functionality
|
||||
|
||||
- A header-only API with no external dependencies.
|
||||
- A set of support libraries ("plugins") for commonly used functionality.
|
||||
|
||||
The usual approach is that PipeWire and PipeWire clients can use the
|
||||
header-only functions to interact with the plugins. Those plugins are
|
||||
usually loaded at runtime (through `dlopen(3)`.
|
||||
usually loaded at runtime (through `dlopen(3)`).
|
||||
|
||||
## Motivation
|
||||
|
||||
# Motivation
|
||||
|
||||
SPA was designed with the following goals in mind:
|
||||
- No dependencies, SPA is shipped as a set of header files that have no dependencies except for the standard c library.
|
||||
|
||||
- No dependencies, SPA is shipped as a set of header files that have no dependencies except for the standard C library.
|
||||
- Very efficient both in space and in time.
|
||||
- Very configurable and usable in many different environments. All aspects
|
||||
of the plugin environment can be configured and changed, like logging,
|
||||
poll loops, system calls etc.
|
||||
- Consistent API
|
||||
- Extensible, new API can be added with minimal effort, existing API can be updated and versioned.
|
||||
poll loops, system calls, etc.
|
||||
- Consistent API.
|
||||
- Extensible; new API can be added with minimal effort, existing API can be updated and versioned.
|
||||
|
||||
The original user of SPA is PipeWire, which uses SPA to implement the
|
||||
low-level multimedia processing plugins, device detection, mainloops, CPU
|
||||
detection and logging, among other things. SPA however can be used outside
|
||||
detection, logging, among other things. SPA however can be used outside
|
||||
of PipeWire with minimal problems.
|
||||
|
||||
## The SPA header-only API
|
||||
|
||||
# The SPA Header-Only API
|
||||
|
||||
A very simple example on how SPA headers work are the \ref spa_utils, a set
|
||||
of utilities commonly required by C projects. SPA functions use the `spa_`
|
||||
|
@ -53,7 +57,7 @@ int main(int argc, char **argv) {
|
|||
\endcode
|
||||
|
||||
|
||||
## SPA Plugins
|
||||
# SPA Plugins
|
||||
|
||||
SPA plugins are shared libraries (`.so` files) that can be loaded at
|
||||
runtime. Each library provides one or more "factories", each of which may
|
||||
|
@ -68,7 +72,7 @@ between the two logging facilities.
|
|||
Please see \ref page_spa_plugins for the details on how to use SPA plugins.
|
||||
|
||||
|
||||
## Further details
|
||||
# Further details
|
||||
|
||||
- \ref api_spa
|
||||
- \subpage page_spa_design
|
||||
|
|
|
@ -3,19 +3,21 @@
|
|||
\ref spa_handle "SPA plugins" are dynamically loadable objects that contain objects and interfaces that
|
||||
can be introspected and used at runtime in any application. This document
|
||||
introduces the basic concepts of SPA plugins. It first covers using the API
|
||||
and then talks about implementing new Plugins.
|
||||
and then talks about implementing new plugins.
|
||||
|
||||
|
||||
## Outline
|
||||
# Outline
|
||||
|
||||
To use a plugin, the following steps are required:
|
||||
- **load** the shared library
|
||||
- **enumerate** the available factories
|
||||
- **enumerate** the interfaces in each factory
|
||||
- **instantiate** the desired interface
|
||||
- **use** the interface-specific functions
|
||||
|
||||
- **Load** the shared library.
|
||||
- **Enumerate** the available factories.
|
||||
- **Enumerate** the interfaces in each factory.
|
||||
- **Instantiate** the desired interface.
|
||||
- **Use** the interface-specific functions.
|
||||
|
||||
In pseudo-code, loading a logger interface looks like this:
|
||||
|
||||
\code{.py}
|
||||
handle = dlopen("$SPA_PLUGIN_PATH/support/libspa-support.so")
|
||||
factory_enumeration_func = dlsym(handle, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)
|
||||
|
@ -71,18 +73,18 @@ factory interfaces:
|
|||
\endverbatim
|
||||
|
||||
|
||||
## Open a plugin
|
||||
# Open A Plugin
|
||||
|
||||
A plugin is opened with a platform specific API. In this example we use
|
||||
`dlopen()` as the method used on Linux.
|
||||
|
||||
A plugin always consists of 2 parts, the vendor path and then the .so file.
|
||||
A plugin always consists of two parts, the vendor path and then the .so file.
|
||||
|
||||
As an example we will load the "support/libspa-support.so" plugin. You will
|
||||
usually use some mapping between functionality and plugin path, as we'll see
|
||||
usually use some mapping between functionality and plugin path as we'll see
|
||||
later, instead of hardcoding the plugin name.
|
||||
|
||||
To dlopen a plugin we then need to prefix the plugin path like this:
|
||||
To `dlopen` a plugin we then need to prefix the plugin path like this:
|
||||
|
||||
\code{.c}
|
||||
#define SPA_PLUGIN_PATH /usr/lib64/spa-0.2/"
|
||||
|
@ -105,7 +107,8 @@ enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME));
|
|||
|
||||
If this symbol is not available, the library is not a valid SPA plugin.
|
||||
|
||||
## Enumerating factories
|
||||
|
||||
# Enumerating Factories
|
||||
|
||||
With the `enum_func` we can now enumerate all the factories in the plugin:
|
||||
|
||||
|
@ -126,7 +129,7 @@ actual new object from it.
|
|||
|
||||
We can enumerate the interfaces that we will find on this new object with
|
||||
the `spa_handle_factory_enum_interface_info()` method. Interface types
|
||||
are simple strings that uniquely define the interface (See also the type
|
||||
are simple strings that uniquely define the interface (see also the type
|
||||
system).
|
||||
|
||||
The name of the factory is a well-known name that describes the functionality
|
||||
|
@ -142,7 +145,8 @@ definitions for common functionality, for example:
|
|||
Usually the name will be mapped to a specific plugin. This way an
|
||||
alternative compatible implementation can be made in a different library.
|
||||
|
||||
## Making a handle
|
||||
|
||||
# Making A Handle
|
||||
|
||||
Once we have a suitable factory, we need to allocate memory for the object
|
||||
it can create. SPA usually does not allocate memory itself but relies on
|
||||
|
@ -173,10 +177,11 @@ The info parameter should contain the same extra properties given in
|
|||
|
||||
The support parameter is an array of `struct spa_support` items. They
|
||||
contain a string type and a pointer to extra support objects. This can
|
||||
be a logging API or a main loop API, for example. Some plugins require
|
||||
be a logging API or a main loop API for example. Some plugins require
|
||||
certain support libraries to function.
|
||||
|
||||
## Retrieving an interface
|
||||
|
||||
# Retrieving An Interface
|
||||
|
||||
When a SPA handle is made, you can retrieve any of the interfaces that
|
||||
it provides:
|
||||
|
@ -195,7 +200,7 @@ spa_log_warn(log, "Hello World!\n");
|
|||
\endcode
|
||||
|
||||
|
||||
## Clearing an object
|
||||
# Clearing An Object
|
||||
|
||||
After you are done with a handle you can clear it with
|
||||
`spa_handle_clear()` and you can unload the library with `dlclose()`.
|
||||
|
@ -215,7 +220,7 @@ will just call the appropriate method in the implementation.
|
|||
|
||||
Interfaces are defined in a header file (for example see
|
||||
`<spa/support/log.h>` for the logger API). It is a self contained
|
||||
definition that you can just use in your application after you dlopen()
|
||||
definition that you can just use in your application after you `dlopen()`
|
||||
the plugin.
|
||||
|
||||
Some interfaces also provide extra fields in the interface, like the
|
||||
|
@ -223,7 +228,8 @@ log interface above that has the log level as a read/write parameter.
|
|||
|
||||
See \ref spa_interface for some implementation details on interfaces.
|
||||
|
||||
## SPA Events
|
||||
|
||||
# SPA Events
|
||||
|
||||
Some interfaces will also allow you to register a callback (a hook or
|
||||
listener) to be notified of events. This is usually when something
|
||||
|
@ -270,7 +276,8 @@ You can remove your listener with:
|
|||
spa_hook_remove(&listener);
|
||||
\endcode
|
||||
|
||||
## API results
|
||||
|
||||
# API Results
|
||||
|
||||
Some interfaces provide API that gives you a list or enumeration of
|
||||
objects/values. To avoid allocation overhead and ownership problems,
|
||||
|
@ -280,8 +287,7 @@ stack and push this to the application without allocation or ownership
|
|||
problems. The application can look at the pushed result and keep/copy
|
||||
only what it wants to keep.
|
||||
|
||||
|
||||
### Synchronous results
|
||||
## Synchronous Results
|
||||
|
||||
Here is an example of enumerating parameters on a node interface.
|
||||
|
||||
|
@ -319,8 +325,7 @@ supported format. After this completes, remove the listener again:
|
|||
spa_hook_remove(&listener);
|
||||
\endcode
|
||||
|
||||
|
||||
### Asynchronous results
|
||||
## Asynchronous Results
|
||||
|
||||
Asynchronous results are pushed to the application in the same way as
|
||||
synchronous results, they are just pushed later. You can check that
|
||||
|
@ -342,9 +347,9 @@ sequence number of the async result code, which can be obtained with:
|
|||
expected_seq = SPA_RESULT_ASYNC_SEQ(res);
|
||||
\endcode
|
||||
|
||||
# Implementing a new plugin
|
||||
# Implementing A New Plugin
|
||||
|
||||
FIXME
|
||||
***FIXME***
|
||||
|
||||
|
||||
|
||||
|
|
144
doc/spa-pod.dox
144
doc/spa-pod.dox
|
@ -3,52 +3,54 @@
|
|||
\ref spa_pod (plain old data) is a sort of data container. It is comparable to
|
||||
DBus Variant or LV2 Atom.
|
||||
|
||||
A POD can express nested structures of Objects (with properties), Vectors,
|
||||
Arrays, sequences and various primitives types. All information in the POD
|
||||
A POD can express nested structures of objects (with properties), vectors,
|
||||
arrays, sequences and various primitives types. All information in the POD
|
||||
is laid out sequentially in memory and can be written directly to
|
||||
storage or exchanged between processes or threads without additional
|
||||
marshalling.
|
||||
|
||||
Each POD is made of a 32 bits size followed by a 32 bits type field,
|
||||
followed by the pod contents. This makes it possible to skip over unknown
|
||||
followed by the POD contents. This makes it possible to skip over unknown
|
||||
POD types. The POD start is always aligned to 8 bytes.
|
||||
|
||||
PODs can be efficiently constructed and parsed in real-time threads without
|
||||
POD's can be efficiently constructed and parsed in real-time threads without
|
||||
requiring memory allocations.
|
||||
|
||||
PODs use the SPA type system for the basic types and containers. See
|
||||
POD's use the SPA type system for the basic types and containers. See
|
||||
the SPA types for more info.
|
||||
|
||||
## Types
|
||||
|
||||
PODs can contain a number of basic SPA types:
|
||||
# Types
|
||||
|
||||
- `SPA_TYPE_None`: no value or a NULL pointer.
|
||||
- `SPA_TYPE_Bool`: a boolean value
|
||||
- `SPA_TYPE_Id`: an enumerated value
|
||||
- `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
|
||||
- various numeral types, 32 and 64 bits.
|
||||
- `SPA_TYPE_String`: a string
|
||||
- `SPA_TYPE_Bytes`: a byte array
|
||||
- `SPA_TYPE_Rectangle`: a rectangle with width and height
|
||||
- `SPA_TYPE_Fraction`: a fraction with numerator and denominator
|
||||
- `SPA_TYPE_Bitmap`: an array of bits
|
||||
POD's can contain a number of basic SPA types:
|
||||
|
||||
PODs can be grouped together in these container types:
|
||||
- `SPA_TYPE_None`: No value or a NULL pointer.
|
||||
- `SPA_TYPE_Bool`: A boolean value.
|
||||
- `SPA_TYPE_Id`: An enumerated value.
|
||||
- `SPA_TYPE_Int`, `SPA_TYPE_Long`, `SPA_TYPE_Float`, `SPA_TYPE_Double`:
|
||||
various numeral types, 32 and 64 bits.
|
||||
- `SPA_TYPE_String`: A string.
|
||||
- `SPA_TYPE_Bytes`: A byte array.
|
||||
- `SPA_TYPE_Rectangle`: A rectangle with width and height.
|
||||
- `SPA_TYPE_Fraction`: A fraction with numerator and denominator.
|
||||
- `SPA_TYPE_Bitmap`: An array of bits.
|
||||
|
||||
- `SPA_TYPE_Array`: an array of equal sized objects
|
||||
- `SPA_TYPE_Struct`: a collection of types and objects
|
||||
- `SPA_TYPE_Object`: an object with properties
|
||||
- `SPA_TYPE_Sequence`: a timed sequence of PODs
|
||||
POD's can be grouped together in these container types:
|
||||
|
||||
PODs can also contain some extra types:
|
||||
- `SPA_TYPE_Array`: An array of equal sized objects.
|
||||
- `SPA_TYPE_Struct`: A collection of types and objects.
|
||||
- `SPA_TYPE_Object`: An object with properties.
|
||||
- `SPA_TYPE_Sequence`: A timed sequence of POD's.
|
||||
|
||||
- `SPA_TYPE_Pointer`: a typed pointer in memory
|
||||
- `SPA_TYPE_Fd`: a file descriptor
|
||||
- `SPA_TYPE_Choice`: a choice of values
|
||||
- `SPA_TYPE_Pod`: a generic type for the POD itself
|
||||
POD's can also contain some extra types:
|
||||
|
||||
# Constructing a POD
|
||||
- `SPA_TYPE_Pointer`: A typed pointer in memory.
|
||||
- `SPA_TYPE_Fd`: A file descriptor.
|
||||
- `SPA_TYPE_Choice`: A choice of values.
|
||||
- `SPA_TYPE_Pod`: A generic type for the POD itself.
|
||||
|
||||
|
||||
# Constructing A POD
|
||||
|
||||
A POD is usually constructed with a `struct spa_pod_builder`. The builder
|
||||
needs to be initialized with a memory region to write into. It is
|
||||
|
@ -59,7 +61,7 @@ not require any memory allocations. The size of the POD can be
|
|||
estimated pretty easily and if the buffer is not large enough, an
|
||||
appropriate error will be generated.
|
||||
|
||||
The code fragment below initializes a pod builder to write into
|
||||
The code fragment below initializes a POD builder to write into
|
||||
the stack allocated buffer.
|
||||
|
||||
\code{.c}
|
||||
|
@ -96,7 +98,7 @@ pod = spa_pod_builder_pop(&b, &f);
|
|||
`spa_pod_builder_pop()` returns a reference to the object we completed
|
||||
on the stack.
|
||||
|
||||
## Using varargs builder.
|
||||
## Using varargs Builder
|
||||
|
||||
We can also use the following construct to make POD objects:
|
||||
|
||||
|
@ -116,10 +118,10 @@ pod = spa_pod_builder_add_struct(&b,
|
|||
SPA_POD_Float(3.1415f));
|
||||
\endcode
|
||||
|
||||
It's not possible to use the varargs builder to make a Sequence or
|
||||
Array, use the normal builder methods for that.
|
||||
It's not possible to use the varargs builder to make a sequence or
|
||||
array, use the normal builder methods for that.
|
||||
|
||||
## Making objects
|
||||
## Making Objects
|
||||
|
||||
POD objects are containers for properties and are comparable to JSON
|
||||
objects.
|
||||
|
@ -131,7 +133,7 @@ spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
|
|||
\endcode
|
||||
|
||||
An object requires an object type (`SPA_TYPE_OBJECT_Props`) and a context
|
||||
id (`SPA_PARAM_Props`). The object type defines the properties that can be
|
||||
ID (`SPA_PARAM_Props`). The object type defines the properties that can be
|
||||
added to the object and their meaning. The SPA type system allows you to
|
||||
make this connection (See the type system).
|
||||
|
||||
|
@ -163,23 +165,23 @@ pod = spa_pod_builder_add_object(&b,
|
|||
SPA_PROP_frequency, SPA_POD_Float(440.0f));
|
||||
\endcode
|
||||
|
||||
## Choice values
|
||||
## Choice Values
|
||||
|
||||
It is possible to express ranges or enumerations of possible
|
||||
values for properties (and to some extend structs). This is achieved
|
||||
with Choice values.
|
||||
with choice values.
|
||||
|
||||
Choice values are really just a choice type and an array of choice values
|
||||
(of the same type). Depending on the choice type, the array values are
|
||||
interpreted in different ways:
|
||||
|
||||
* `SPA_CHOICE_None`: no choice, first value is current
|
||||
* `SPA_CHOICE_Range`: range: default, min, max
|
||||
* `SPA_CHOICE_Step`: range with step: default, min, max, step
|
||||
* `SPA_CHOICE_Enum`: enum: default, alternative,...
|
||||
* `SPA_CHOICE_Flags`: bitmask of flags
|
||||
- `SPA_CHOICE_None`: No choice, first value is current.
|
||||
- `SPA_CHOICE_Range`: Range: default, min, max.
|
||||
- `SPA_CHOICE_Step`: Range with step: default, min, max, step.
|
||||
- `SPA_CHOICE_Enum`: Enum: default, alternative,...
|
||||
- `SPA_CHOICE_Flags`: Bitmask of flags.
|
||||
|
||||
Let's illustrate this with a Props object that specifies a range of
|
||||
Let's illustrate this with a props object that specifies a range of
|
||||
possible values for the frequency:
|
||||
|
||||
\code{.c}
|
||||
|
@ -195,8 +197,8 @@ pod = spa_pod_builder_pop(&b, &f2);
|
|||
pod = spa_pod_builder_pop(&b, &f);
|
||||
\endcode
|
||||
|
||||
As you can see, first push the choice as a Range, then the values. A Range
|
||||
choice expects at least 3 values, the default value, minimum and maximum
|
||||
As you can see, first push the choice as a range, then the values. A range
|
||||
choice expects at least three values, the default value, minimum and maximum
|
||||
values. There is a shortcut for this as well using varargs:
|
||||
|
||||
\code{.c}
|
||||
|
@ -205,7 +207,7 @@ pod = spa_pod_builder_add_object(&b,
|
|||
SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f));
|
||||
\endcode
|
||||
|
||||
## Choice examples
|
||||
## Choice Examples
|
||||
|
||||
This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
|
||||
enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects:
|
||||
|
@ -253,16 +255,17 @@ pod = spa_pod_builder_add_object(&b,
|
|||
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
|
||||
\endcode
|
||||
|
||||
# Parsing a POD
|
||||
|
||||
Parsing a POD usually consists of
|
||||
# Parsing A POD
|
||||
|
||||
* validating if raw bytes + size can contain a valid pod
|
||||
* inspecting the type of a pod
|
||||
* looping over the items in an object or struct
|
||||
* getting data out of PODs.
|
||||
Parsing a POD usually consists of:
|
||||
|
||||
## Validating bytes
|
||||
- Validating if raw bytes + size can contain a valid POD.
|
||||
- Inspecting the type of a POD.
|
||||
- Looping over the items in an object or struct.
|
||||
- Getting data out of POD's.
|
||||
|
||||
## Validating Bytes
|
||||
|
||||
Use `spa_pod_from_data()` to check if maxsize of bytes in data contain
|
||||
a POD at the size bytes starting at offset. This function checks that
|
||||
|
@ -273,7 +276,7 @@ struct spa_pod *pod;
|
|||
pod = spa_pod_from_data(data, maxsize, offset, size);
|
||||
\endcode
|
||||
|
||||
## Checking the type of POD
|
||||
## Checking The Type Of POD
|
||||
|
||||
Use one of `spa_pod_is_bool()`, `spa_pod_is_int()`, etc to check
|
||||
for the type of the pod. For simple (non-container) types,
|
||||
|
@ -283,9 +286,9 @@ extract the value of the pod.
|
|||
`spa_pod_is_object_type()` can be used to check if the POD contains
|
||||
an object of the expected type.
|
||||
|
||||
## Struct fields
|
||||
## Struct Fields
|
||||
|
||||
To iterate over the fields of a Struct use:
|
||||
To iterate over the fields of a struct use:
|
||||
|
||||
\code{.c}
|
||||
struct spa_pod *pod, *obj;
|
||||
|
@ -294,7 +297,7 @@ SPA_POD_STRUCT_FOREACH(obj, pod) {
|
|||
}
|
||||
\endcode
|
||||
|
||||
For parsing Structs it is usually much easier to use the parser
|
||||
For parsing structs it is usually much easier to use the parser
|
||||
below.
|
||||
|
||||
## Object Properties
|
||||
|
@ -363,7 +366,7 @@ And finally exit the container again:
|
|||
spa_pod_parser_pop(&p, &f);
|
||||
\endcode
|
||||
|
||||
## Parser with variable arguments
|
||||
## Parser With Variable Arguments
|
||||
|
||||
In most cases, parsing objects is easier with the variable argument
|
||||
functions. The parse function look like the mirror image of the builder
|
||||
|
@ -408,15 +411,15 @@ spa_pod_parser_get_object(&p,
|
|||
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels));
|
||||
\endcode
|
||||
|
||||
It is not possible to parse a Sequence or Array with the parser.
|
||||
It is not possible to parse a sequence or array with the parser.
|
||||
Use the iterator for this.
|
||||
|
||||
## Choice values
|
||||
## Choice Values
|
||||
|
||||
The parser will handle Choice values as long as they are of type
|
||||
None. It will then parse the single value from the choice. When
|
||||
The parser will handle choice values as long as they are of type
|
||||
`none`. It will then parse the single value from the choice. When
|
||||
dealing with other choice values, it's possible to parse the
|
||||
property values into a `struct spa_pod` and then inspect the Choice
|
||||
property values into a `struct spa_pod` and then inspect the choice
|
||||
manually, if needed.
|
||||
|
||||
Here is an example of parsing the format values as a POD:
|
||||
|
@ -432,9 +435,9 @@ spa_pod_parser_get_object(&p,
|
|||
\endcode
|
||||
|
||||
`spa_pod_get_values()` is a useful function. It returns a
|
||||
`struct spa_pod*` with and array of values. For normal PODs
|
||||
and Choice None values, it simply returns the POD and 1 value.
|
||||
For other Choice values it returns the Choice type and an array
|
||||
`struct spa_pod*` with and array of values. For normal POD's
|
||||
and choice none values, it simply returns the POD and one value.
|
||||
For other choice values it returns the choice type and an array
|
||||
of values:
|
||||
|
||||
\code{.c}
|
||||
|
@ -464,15 +467,16 @@ default:
|
|||
}
|
||||
\endcode
|
||||
|
||||
|
||||
# Filter
|
||||
|
||||
Given 2 pod objects of the same type (Object, Struct, ..) one can
|
||||
run a filter and generate a new pod that only contains values that
|
||||
are compatible with both input pods.
|
||||
Given two POD objects of the same type (object, struct, ..) one can
|
||||
run a filter and generate a new POD that only contains values that
|
||||
are compatible with both input POD's.
|
||||
|
||||
This is, for example, used to find a compatible format between two ports.
|
||||
|
||||
As an example we can run a filter on two simple PODs:
|
||||
As an example we can run a filter on two simple POD's:
|
||||
|
||||
\code{.c}
|
||||
pod = spa_pod_builder_add_object(&b,
|
||||
|
@ -511,7 +515,7 @@ result = spa_pod_builder_add_object(&b,
|
|||
SPA_FORMAT_AUDIO_format, SPA_AUDIO_FORMAT_S16);
|
||||
\endcode
|
||||
|
||||
# POD layout
|
||||
# POD Layout
|
||||
|
||||
Each POD has a 32 bits size field, followed by a 32 bits type field. The size
|
||||
field specifies the size following the type field.
|
||||
|
|
|
@ -10,7 +10,8 @@ PipeWire API step-by-step with simple short examples.
|
|||
- \subpage page_tutorial5
|
||||
- \subpage page_tutorial6
|
||||
|
||||
## More example programs
|
||||
|
||||
# More Example Programs
|
||||
|
||||
- \ref audio-src.c "": \snippet{doc} audio-src.c title
|
||||
- \ref audio-dsp-filter.c "": \snippet{doc} audio-dsp-filter.c title
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial1 Tutorial - Part 1: Getting started
|
||||
/** \page page_tutorial1 Tutorial - Part 1: Getting Started
|
||||
|
||||
|
||||
\ref page_tutorial "Index" | \ref page_tutorial2
|
||||
|
@ -7,7 +7,8 @@ In this tutorial we show the basics of a simple PipeWire application.
|
|||
Use this tutorial to get started and help you set up your development
|
||||
environment.
|
||||
|
||||
## Initialization
|
||||
|
||||
# Initialization
|
||||
|
||||
Let get started with the simplest application.
|
||||
|
||||
|
@ -15,10 +16,11 @@ Let get started with the simplest application.
|
|||
|
||||
Before you can use any PipeWire functions, you need to call `pw_init()`.
|
||||
|
||||
## Compilation
|
||||
|
||||
# Compilation
|
||||
|
||||
PipeWire provides a pkg-config file named `libpipewire-0.3` (note: the version
|
||||
suffix may change with future releases of pipewire).
|
||||
suffix may change with future releases of PipeWire).
|
||||
To compile the simple test application, copy it into a test1.c file and
|
||||
use pkg-config to provide the required dependencies:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial2 Tutorial - Part 2: Enumerating objects
|
||||
/** \page page_tutorial2 Tutorial - Part 2: Enumerating Objects
|
||||
|
||||
\ref page_tutorial1 | \ref page_tutorial "Index" | \ref page_tutorial3
|
||||
|
||||
|
@ -125,4 +125,5 @@ continue forever. In the next tutorial we'll see how we can nicely
|
|||
exit our application after we received all server objects.
|
||||
|
||||
\ref page_tutorial1 | \ref page_tutorial "Index" | \ref page_tutorial3
|
||||
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial3 Tutorial - Part 3: Forcing a roundtrip
|
||||
/** \page page_tutorial3 Tutorial - Part 3: Forcing A Roundtrip
|
||||
|
||||
\ref page_tutorial2 | \ref page_tutorial "Index" | \ref page_tutorial4
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial4 Tutorial - Part 4: Playing a tone
|
||||
/** \page page_tutorial4 Tutorial - Part 4: Playing A Tone
|
||||
|
||||
\ref page_tutorial3 | \ref page_tutorial "Index" | \ref page_tutorial5
|
||||
|
||||
|
@ -57,13 +57,12 @@ and `struct pw_core` automatically.
|
|||
|
||||
In the properties we need to give as much information about the stream as we
|
||||
can so that the session manager can make good decisions about how and where
|
||||
to route this stream. There are 3 important properties to configure:
|
||||
to route this stream. There are three important properties to configure:
|
||||
|
||||
* `PW_KEY_MEDIA_TYPE` The media type, like Audio, Video, Midi
|
||||
* `pw_KEY_MEDIA_CATEGORY` The category, like Playback, Capture, Duplex, Monitor
|
||||
* `PW_KEY_MEDIA_ROLE` The media role, like Movie, Music, Camera, Screen,
|
||||
Communication, Game, Notification, DSP,
|
||||
Production, Accessibility, Test
|
||||
- `PW_KEY_MEDIA_TYPE`: The media type; like Audio, Video, MIDI.
|
||||
- `PW_KEY_MEDIA_CATEGORY`: The category; like Playback, Capture, Duplex, Monitor.
|
||||
- `PW_KEY_MEDIA_ROLE`: The media role; like Movie, Music, Camera, Screen,
|
||||
Communication, Game, Notification, DSP, Production, Accessibility, Test.
|
||||
|
||||
The properties are owned by the stream and freed when the stream is destroyed
|
||||
later.
|
||||
|
@ -122,15 +121,14 @@ Now we're ready to connect the stream and run the main loop:
|
|||
To connect we specify that we have a `PW_DIRECTION_OUTPUT` stream. `PW_ID_ANY`
|
||||
means that we are ok with connecting to any consumer. Next we set some flags:
|
||||
|
||||
* `PW_STREAM_FLAG_AUTOCONNECT` automatically connect this stream. This instructs
|
||||
the session manager to link us to some consumer.
|
||||
* `PW_STREAM_FLAG_MAP_BUFFERS` mmap the buffers for us so we can access the
|
||||
memory. If you don't set these flags you have
|
||||
either work with the fd or mmap yourself.
|
||||
* `PW_STREAM_FLAG_RT_PROCESS` Run the process function in the realtime thread.
|
||||
Only use this if the process function only
|
||||
uses functions that are realtime safe, this means
|
||||
no allocation or file access or any locking.
|
||||
- `PW_STREAM_FLAG_AUTOCONNECT`: Automatically connect this stream. This instructs
|
||||
the session manager to link us to some consumer.
|
||||
- `PW_STREAM_FLAG_MAP_BUFFERS`: mmap the buffers for us so we can access the
|
||||
memory. If you don't set these flags you have either work with the fd or mmap
|
||||
yourself.
|
||||
- `PW_STREAM_FLAG_RT_PROCESS`: Run the process function in the realtime thread.
|
||||
Only use this if the process function only uses functions that are realtime
|
||||
safe, this means no allocation or file access or any locking.
|
||||
|
||||
And last we pass the extra parameters for our stream. Here we only have the
|
||||
allowed formats (`SPA_PARAM_EnumFormat`).
|
||||
|
@ -140,11 +138,11 @@ Running the mainloop will then start processing and will result in our
|
|||
|
||||
The main program flow of the process function is:
|
||||
|
||||
* `pw_stream_dequeue_buffer()` to obtain a buffer to write into.
|
||||
* Get pointers in buffer memory to write to
|
||||
* write data into buffer
|
||||
* adjust buffer with number of written bytes, offset, stride,
|
||||
* `pw_stream_queue_buffer()` to queue the buffer for playback.
|
||||
- `pw_stream_dequeue_buffer()` to obtain a buffer to write into.
|
||||
- Get pointers in buffer memory to write to.
|
||||
- Write data into buffer.
|
||||
- Adjust buffer with number of written bytes, offset, stride.
|
||||
- `pw_stream_queue_buffer()` to queue the buffer for playback.
|
||||
|
||||
\snippet tutorial4.c on_process
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial5 Tutorial - Part 5: Capturing video frames
|
||||
/** \page page_tutorial5 Tutorial - Part 5: Capturing Video Frames
|
||||
|
||||
\ref page_tutorial4 | \ref page_tutorial "Index" | \ref page_tutorial6
|
||||
|
||||
|
@ -141,7 +141,6 @@ stream mmap the data for us.
|
|||
And last we pass the extra parameters for our stream. Here we only have the
|
||||
allowed formats (`SPA_PARAM_EnumFormat`).
|
||||
|
||||
|
||||
Running the mainloop will start the connection and negotiation process.
|
||||
First our `param_changed` event will be called with the format that was
|
||||
negotiated between our stream and the camera. This is always something that
|
||||
|
@ -160,7 +159,7 @@ static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *
|
|||
return;
|
||||
\endcode
|
||||
|
||||
First check if there is a param. A NULL param means that it is cleared. The id
|
||||
First check if there is a param. A NULL param means that it is cleared. The ID
|
||||
of the param tells you what param it is. We are only interested in Format
|
||||
param (`SPA_PARAM_Format`).
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** \page page_tutorial6 Tutorial - Part 6: Binding objects
|
||||
/** \page page_tutorial6 Tutorial - Part 6: Binding Objects
|
||||
|
||||
\ref page_tutorial5 | \ref page_tutorial "Index"
|
||||
|
||||
|
|
Loading…
Reference in a new issue