PipeWire 1.2.1
|
PipeWire is a graph-based processing framework, that focuses on handling multimedia data (audio, video and MIDI mainly).
A PipeWire graph is composed of nodes. Each node takes an arbitrary number of inputs called ports, does some processing over this multimedia data, and sends data out of its output ports. The edges in the graph are here called links. They are capable of connecting an output port to an input port.
Nodes can have an arbitrary number of ports. A node with only output ports is often called a source, and a sink is a node that only possesses input ports.
The PipeWire server provides the implementation of some of these nodes itself. Most importantly, it uses alsa-lib like any other ALSA client to expose statically configured ALSA devices as nodes. For example
Similar mechanisms exist to interface with and accommodate applications which use JACK or Pulseaudio.
NOTE: pw-jack
modifies the LD_LIBRARY_PATH
environment variable so that applications will load PipeWire’s reimplementation of the JACK client libraries instead of JACK’s own libraries. This results in JACK clients being redirected to PipeWire.
Other nodes are implemented by PipeWire clients.
PipeWire clients can be any process. They can speak to the PipeWire server through a UNIX domain socket using the PipeWire native protocol. Besides implementing nodes, they may control the graph.
The PipeWire server itself does not perform any management of the graph; context-dependent behaviour such as monitoring for new ALSA devices, and configuring them so that they appear as nodes, or linking nodes is not done automatically. It rather provides an API that allows spawning, linking and controlling these nodes. This API is then relied upon by clients to control the graph structure, without having to worry about the graph execution process.
A recommended pattern that is often used is a single client be a daemon that deals with the session and policy management. Two implementations are known as of today:
With the nodes which they implement, clients can send multimedia data into the graph or obtain multimedia data from the graph. A client can create multiple PipeWire nodes. That allows one to create more complex applications; a browser would for example be able to create a node per tab that requests the ability to play audio, letting the session manager handle the routing: This allows the user to route different tab sources to different sinks. Another example would be an application that requires many inputs.
The current state of the PipeWire server and its capabilities, and the PipeWire graph are exposed towards clients – including introspection tools like pw-dump
– as a collection of objects, each of which has a specific type. These objects have associated parameters, and properties, methods, events, and permissions.
Parameters of an object are data with a specific, well defined meaning, which can be modified and read-out in a controlled fashion through the PipeWire API. They are used to configure the object at run-time. Parameters are the key that allow WirePlumber to negotiate data formats and port configuration with nodes by providing information such as:
Properties of an object are additional data which have been attached on the behalf of modules and of which the PipeWire server has no native understanding. Certain properties are, by convention, expected for specific object types.
Each object type has a list of methods that it needs to implement.
The session manager is responsible for defining the list of permissions each client has. Each permission entry is an object ID and four flags. The four flags are:
The following are the known types and their most important, specialized parameters and methods:
The core is the heart of the PipeWire server. There can only be one core per server and it has the identifier zero. It represents global properties of the server.
A client object is the representation of an open connection with a client process with the server.
Modules are dynamic libraries that are loaded at run time in the clients and in the server and do arbitrary things, such as creating devices or provide methods to create links, nodes, etc.
Modules in PipeWire can only be loaded in their own process. A client, for example, can not load a module in the server.
Nodes are the core data processing entities in PipeWire. They may produce data (capture devices, signal generators, ...), consume data (playback devices, network endpoints, ...) or both (filters). Notes have a method process
, which eats up data from input ports and provides data for each output port.
Ports are the entry and exit point of data for a Node. A port can either be used for input or output (but not both). For nodes that work with audio, one type of configuration is whether they have dsp
ports or a passthrough
port. In dsp
mode, there is one port for channel of multichannel audio (so two ports for stereo audio, for example), and data is always in 32-bit floating point format. In passthrough
mode, there is one port for multichannel data in a format that is negotiated between ports.
Data flows between nodes when there is a Link between their ports. Links may be "passive"
in which case the existence of the link does not automatically cause data to flow between those nodes (some link in the graph must be "active"
for the graph to have data flow).
A device is a handle representing an underlying API, which is then used to create nodes or other devices. Examples of devices are ALSA PCM cards or V4L2 devices. A device has a profile, which allows one to configure them.
A factory is an object whose sole capability is to create other objects. Once a factory is created, it can only emit the type of object it declared. Those are most often delivered as a module: the module creates the factory and stays alive to keep it accessible for clients.
Every object implement at least the add_listener method, that allows any client to register event listeners. Events are used through the PipeWire API to expose information about an object that might change over time (the state of a node for example).
The PipeWire server and PipeWire clients use the PipeWire API through their respective pw_context
, the so called PipeWire context. When a PipeWire context is created, it finds and parses a configuration file from the filesystem according to the rules of loading configuration files.