Skip to content
Snippets Groups Projects
configuration.md 16.5 KiB
Newer Older
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441

WirePlumber is a heavily modular daemon. By itself, it doesn't do anything
except load the configured modules. All the rest of the logic is implemented
inside those modules.

Modular design ensures that it is possible to swap the implementation of
specific functionality without having to re-implement the rest of it, allowing
flexibility on target-sensitive parts, such as policy management and
making use of non-standard hardware.

## `wireplumber.conf`

This is WirePlumber's main configuration file. It is read at startup, before
connecting to the PipeWire daemon. Its purpose is to list all the modules
that need to be loaded by WirePlumber.

The format of this file is custom and resembles a script with commands:

```
# comment
command parameter1 parameter2 ...
```

Lines are executed in the order they appear and each of them executes an
action defined by the command. Lines starting with `#` are treated as comments
and ignored. Possible commands are:

* `add-spa-lib`

  Associates SPA plugin names with the names of the SPA modules that they
  can be loaded from. This takes 2 parameters: a name pattern and a library name.

  This actually does not load the SPA plugin, it only calls `pw_core_add_spa_lib`
  with the 2 paramteres given as arguments. As a consequence, it is safe to
  call this even if the SPA module is not actually installed on the system.

  Example:
  ```
  add-spa-lib api.alsa.* alsa/libspa-alsa
  ```

  In this example, we let `libpipewire` know that any SPA plugin whose name
  starts with `api.alsa.` can be loaded from the SPA module
  `alsa/libspa-alsa.so` (relative to the standard SPA modules directory).

* `load-pipewire-module`

  Loads a `libpipewire` module. This is similar to the `load-module` commands
  that would appear on `pipewire.conf`, the configuration file of the PipeWire
  daemon.

  This takes at least 1 parameter, the module name, and optionally any module
  arguments, in the format that they would be given in `pipewire.conf`

  Format:
  ```
  load-pipewire-module module-name some-argument some-property=value
  ```
  Example:
  ```
  load-pipewire-module libpipewire-module-client-device
  ```

  This command does not affect the PipeWire daemon by any means. It exists
  simply to allow loading `libpipewire` modules in the pipewire core that
  runs inside WirePlumber. This is usually useful to load pipewire protocol
  extensions, so that you can export custom objects to PipeWire and other
  clients.

* `load-module`

  Loads a WirePlumber module. This takes 2 arguments and an optional parameter
  block.

  Format:
  ```
  load-module ABI module-name {
    "parameter": <"value">
  }
  ```

  The `ABI` parameter specifies the binary interface that WirePlumber shall use
  to load this module. Currently, the only supported ABI is `C`. It exists to
  allow future expansion, writing modules in other languages.

  The `module-name` should be the name of the `.so` file without the `.so`
  extension.

  Optionally, if the `load-module` line ends with a `{`, the next lines up to
  and including the next matching `}` are treated as a parameter block.
  This block essentially is a
  [GVariant](https://developer.gnome.org/glib/stable/glib-GVariant.html)
  of type
  [`a{sv}`](https://developer.gnome.org/glib/stable/gvariant-format-strings.html)
  in the
  [GVariant Text Format](https://developer.gnome.org/glib/stable/gvariant-text.html).
  As a rule of thumb, parameter names in this block must always be strings
  enclosed in double quotes, the separation between names and values is done
  with the `:` character and values, regardless of their inner type, must always
  be enclosed in `<` `>`.

  Note that starting the parameter block on the next line is an error. The
  starting brace (`{`) must always be on the `load-module` line.

  Example:
  ```
  load-module C libwireplumber-module-monitor {
    "factory": <"api.alsa.enum.udev">,
    "flags": <["use-adapter", "activate-devices"]>
  }
  ```

  Parameters are module-dependent. They are passed as a GVariant in the
  module's initialization function and it is up to the module to interpret
  their meaning. WirePlumber does not have any reserved parameters.

## Location of configuration files

WirePlumber's default location of its configuration files is determined at
compile time by the build system. Typically, it ends up being `/etc/wireplumber`.

In more detail, this is controlled by the `--sysconfdir` meson option. When
this is set to an absolute path, such as `/etc`, the location of the
configuration files is set to be `$sysconfdir/wireplumber`. When this is set
to a relative path, such as `etc`, then the installation prefix (`--prefix`)
is prepended to the path: `$prefix/$sysconfdir/wireplumber`

WirePlumber expects its `wireplumber.conf` to reside in that directory.
It is possible to override that at runtime by setting the
`WIREPLUMBER_CONFIG_FILE` environment variable:

```
WIREPLUMBER_CONFIG_FILE=src/config/wireplumber.conf wireplumber
```

It is also possible to override the whole configuration directory, so that
all other configuration files are being read from a different location as well,
by setting the `WIREPLUMBER_CONFIG_DIR` environment variable:
```
WIREPLUMBER_CONFIG_DIR=src/config wireplumber
```

## Location of modules

### WirePlumber modules

Like with configuration files, WirePlumber's default location of its modules is
determined at compile time by the build system. Typically, it ends up being
`/usr/lib/wireplumber-0.1` (or `/usr/lib/<arch-triplet>/wireplumber-0.1` on
multiarch systems)

In more detail, this is controlled by the `--libdir` meson option. When
this is set to an absolute path, such as `/lib`, the location of the
modules is set to be `$libdir/wireplumber-$abi_version`. When this is set
to a relative path, such as `lib`, then the installation prefix (`--prefix`)
is prepended to the path: `$prefix/$libdir/wireplumber-$abi_version`.

It is possible to override this directory at runtime by setting the
`WIREPLUMBER_MODULE_DIR` environment variable:
```
WIREPLUMBER_MODULE_DIR=build/modules wireplumber
```

### PipeWire and SPA modules

PipeWire and SPA modules are not loaded from the same location as WirePlumber's
modules. They are loaded from the location that PipeWire loads them.

It is also possible to override these locations by using environment variables:
`SPA_PLUGIN_DIR` and `PIPEWIRE_MODULE_DIR`. For more details, refer to
PipeWire's documentation.

# module-monitor

This module internally loads a SPA "device" object which enumerates all the
devices of a certain subsystem. Then it listens for "node" objects that are
being created by this device and exports them to PipeWire, after adjusting
their properties to provide enough context.

`module-monitor` does not read any configuration files, however, it supports
configuration through parameters defined in the main `wireplumber.conf`.
Possible parameters are:

* `factory`

  A string that specifies the name of the SPA factory that loads the intial
  "device" object.

  Well-known factories are:

  * "api.alsa.enum.udev" - Discovers ALSA devices via udev
  * "api.v4l2.enum.udev" - Discovers V4L2 devices via udev
  * "api.bluez5.enum.dbus" - Discovers bluetooth devices by calling bluez5 API via D-Bus

 * `flags`

    An array of strings that enable specific functionality in the monitor.
    Possible flags include:

    * "use-adapter"

      Instructs the monitor to wrap all the created nodes in an "adapter"
      SPA node, which provides automatic port splitting/merging and format/rate
      conversion. This should be always enabled for audio device nodes.

    * "local-nodes"

      Instructs the monitor to run all the created nodes locally in in the
      WirePlumber process, instead of the default behavior which is to create
      the nodes in the PipeWire process. This is useful for bluetooth nodes,
      which should run outside of the main PipeWire process for performance
      reasons.

    * "activate-devices"

      Instructs the monitor to automatically set the device profile to "On",
      so that the nodes are created. If not specified, the profile must be
      set externally by the user before any nodes appear.

# module-config-endpoint

This module creates endpoints when WirePlumber detects new nodes in the
pipewire graph. Nodes themselves can be created in two ways:
Device modes are being created by "monitors" that watch a specific subsystem
(udev, bluez, etc...) for devices. Client nodes are being created by client
applications that try to stream to/from pipewire. As soon as a node is created,
the `module-config-endpoint` iterates through all the `.endpoint` configuration
files, in the order that is determined by the `match-node.priority` field,
and tries to match the node to the node description in the `[match-node]` table.
Upon a successful match, a new endpoint that follows the description in the
`[endpoint]` table is created.

## `*.endpoint` configuration files

These files are TOML v0.5 files. At the top-level, they must contain exactly
2 tables: `[match-node]` and `[endpoint]`

The `[match-node]` table contains properties that match a pipewire node that
exists on the graph. Possible fields of this table are:

* `priority`

  Specifies the order in which the `.endpoint` files are being searched for a
  match with a node. If a node matches the description of more than one
  `.endpoint` file, the one with the highest priority wins.

  The type of this field is unsigned integer. Bigger numbers mean higher
  priority.

* `properties`

  This is a TOML array of tables, where each table must contain two fields:
  `name` and `value`, both being strings. Each table describes a match against
  one of the pipewire properties of the node. For a successful node match, all
  the described properties must match with the node.

  The value of the `name` field must match exactly the name of the pipewire
  property, while the value of the `value` field can contain '*' (wildcard)
  and '?' (joker), adhering to the rules of the
  [GLib g_pattern_match() function](https://developer.gnome.org/glib/stable/glib-Glob-style-pattern-matching.html).

  When writing `.endpoint` files, a useful utility that you can use to list
  device node properties is:

  ```
  $ wireplumber-cli device-node-props
  ```

  Another way to figure out some of these properties *for ALSA nodes* is
  by parsing the aplay/arecord output. For example, this line from `aplay -l`
  is interpreted as follows:

  ```
  card 0: PCH [HDA Intel PCH], device 2: ALC3246 [ALC3246 Analog]
  ```

  ```
  { name = "api.alsa.path", value = "hw:0,2" },
  { name = "api.alsa.card", value = "0" },
  { name = "api.alsa.card.id", value = "PCH" },
  { name = "api.alsa.card.name", value = "HDA Intel PCH" },
  { name = "api.alsa.pcm.device", value = "2" },
  { name = "api.alsa.pcm.id", value = "ALC3246" },
  { name = "api.alsa.pcm.name", value = "ALC3246 Analog" },
  ```

The `[endpoint]` table contains a description of the endpoint to be created.
Possible fields of this table are:

* `type`

  Required. Specifies the factory to be used for construction.
  The only well-known factory at the moment of writing is: `pw-audio-softdsp-endpoint`

* `direction`

  Required. Can be set to either `"sink"` or `"source"`. Specifies the
  direction of the media flow of this endpoint. A `source` is an endpoint that
  produces data (i.e. an audio capture device or a playback application) and
  a `sink` is an endpoint that consumes data (audio playback device or
  capture application).

* `name`

  Optional. The name of the newly created endpoint. If not specified,
  the endpoint is named after the node (from the `node.name` property of the node).

* `media_class`

  Optional. A string that specifies an override for the `media.class` property
  of the node. It can be used in special circumstances to declare that an
  endpoint is dealing with a different type of data. This is only useful in
  combination with a policy implementation that is aware of this media class.

* `priority`

  Optional. An unsigned integer that specifies the order in which endpoints are
  chosen to be the default of a specific device group. Possible device groups
  are (determined by the endpoint's `media.class`):

  * Audio/Sink
  * Audio/Source
  * Video/Source

  Every time a new device endpoint is created, wireplumber picks the "default"
  of the group that it belongs to, based on this priority number: the endpoint
  with the biggest priority number wins.

  If not specified, the default priority of an endpoint is equal to zero
  (i.e. the lowest priority).

* `streams`

  Optional. Specifies the name of a `.streams` file that contains the
  descriptions of the streams to create for this endpoint. This currently
  specific to the implementation of the `pw-audio-softdsp-endpoint` and might
  change in the future.

## `*.streams` configuration files

These files contain lists of streams with their names and priorities.
They are TOML v0.5 files.

Each `.streams` file must contain exactly one top-level array of tables,
called `streams`. Every table must contain exactly two fields:
`name` and `priority`.

The `name` of each stream is used to create the streams on new endpoints.

The `priority` of each stream is being interpreted by the policy module to
apply restrictions on which app can use the stream at a given time.

# module-config-policy

This module implements demo-quality policy management that is partly driven
by configuration files. The configuration files that this module reads are
described below:

## `*.endpoint-link`

These files contain rules to link endpoints with each other.
They are TOML v0.5 files.

Endpoints are normally created by another module, such
as `module-config-endpoint` which is described above.
As soon as an endpoint is created, the `module-config-policy` uses the
information gathered from the `.endpoint-link` files in order to create a
link to another endpoint.

`.endpoint-link` files can contain 3 top-level tables:
* `[match-endpoint]`, required
* `[target-endpoint]`, optional
* `[endpoint-link]`, required

The `[match-endpoint]` table contains properties that match an endpoint that
exists on the graph. Possible fields of this table are:

* `priority`

  Specifies the order in which the `.endpoint-link` files are being searched
  for a match with an endpoint. If an endpoint matches the description of more
  than one `.endpoint-link` file, the one with the highest priority wins.

  The type of this field is unsigned integer. Bigger numbers mean higher
  priority.

* `direction`

  Required. Can be set to either `"sink"` or `"source"`. Specifies the
  direction of the media flow of this endpoint. A `source` is an endpoint that
  produces data (i.e. an audio capture device or a playback application) and
  a `sink` is an endpoint that consumes data (audio playback device or
  capture application).

* `name`

  Optional. The name of the endpoint. It is possible to use wildcards here to
  match only parts of the name.

* `media_class`

  Optional. A string that specifies the `media.class` that the endpoint
  must have in order to match.

* `properties`

  This is a TOML array of tables, where each table must contain two fields:
  `name` and `value`, both being strings. Each table describes a match against
  one of the pipewire properties of the endpoint. For a successful endpoint
  match, all the described properties must match with the endpoint.

The `[target-endpoint]` table contains properties that match an endpoint that
exists on the graph. The purpose of this table is to match a second endpoint
that the original matching endpoint from `[match-endpoint]` will be linked to.
If not specified, `module-config-policy` will look for the session "default"
endpoint for the type of media that the matching endpoint produces or consumes
and will use that as a target. Possible fields of this table are:

* `direction`, `name`, `media_class`, `properties`

  All these fields are permitted and behave exactly as described above for the
  `[match-endpoint]` table.

* `stream`

  This field specifies a stream name that the link will use on the target
  endpoint. If it is not specified, the stream name is acquired from the
  `media.role` property of the matching endpoint. If specified, the value of
  this field overrides the `media.role`.

The `[endpoint-link]` table specifies properties of the link. Possible fields
of this table are:

* `keep`

  A boolean field. If set to true, the link is always kept active and ignores
  policy rules regarding corking or stream priority. This link will also not
  affect the rules for other links. For example, if a keep=true link is
  activating a high priority stream, lower priority streams can still work on
  the same target endpoint for links with keep=false.