mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Documentation Updates
This commit is contained in:
parent
8afe5fe0f0
commit
c71db353f1
27 changed files with 513 additions and 498 deletions
|
|
@ -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
|
PipeWire supports sharing Direct Memory Access buffers (DMA-BUFs) between
|
||||||
clients via the `SPA_DATA_DmaBuf` data type. However properly negotiating
|
clients via the `SPA_DATA_DmaBuf` data type. However properly negotiating
|
||||||
DMA-BUF support on both the producer and the consumer side require following
|
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
|
a specific procedure. This page describes said procedure by using events and
|
||||||
methods from the filter or stream API.
|
methods from the filter or stream API.
|
||||||
|
|
||||||
Note: This article focuses mostly on DMA-BUF sharing from arbitrary devices,
|
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
|
like discrete GPUs. For using DMA-BUFs created by v4l2 please refer to the
|
||||||
corresponding paragraph.
|
corresponding paragraph.
|
||||||
|
|
||||||
# Capability negotiations
|
# Capability Negotiations
|
||||||
|
|
||||||
The capability negotiation for DMA-BUFs is complicated by the fact, that a
|
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
|
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
|
To prioritise DMA-BUFs place those `SPA_PARAM_EnumFormat` containing modifiers
|
||||||
first, when emitting them to PipeWire.
|
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
|
When the `param_changed` hook is called for a `SPA_PARAM_Format` the client
|
||||||
has to parse the `spa_pod` directly. Use
|
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
|
announce sufficient capabilities or fallback to shared memory buffers when
|
||||||
possible.
|
possible.
|
||||||
|
|
||||||
### For consumers
|
### For Consumers
|
||||||
|
|
||||||
Use `spa_format_video_raw_parse` to get the format and modifier.
|
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
|
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
|
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:
|
- modifier-less:
|
||||||
In this case only the modifier `DRM_FORMAT_MOD_INVALID` was announced with
|
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.
|
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).
|
(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
|
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
|
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
|
modifier. Fixate on that `EnumFormat` by announcing a `SPA_PARAM_EnumFormat` with
|
||||||
only one modifier in the `SPA_CHOICE_Enum` and without the
|
only one modifier in the `SPA_CHOICE_Enum` and without the
|
||||||
`SPA_POD_PROP_FLAG_DONT_FIXATE` flag, followed by the previous announced
|
`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.
|
`SPA_PARAM_Format` as described below.
|
||||||
If the `SPA_PARAM_Format` contains a modifier key, without the flag
|
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
|
`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
|
possible modifiers contains `DRM_FORMAT_MOD_INVALID`, fall back to allocating
|
||||||
without an explicit modifier if the graphics API allows it.
|
without an explicit modifier if the graphics API allows it.
|
||||||
|
|
||||||
## add_buffer hook
|
## add_buffer Hook
|
||||||
|
|
||||||
This is relevant for producers.
|
This is relevant for producers.
|
||||||
|
|
||||||
Allocate a DMA-BUF only using the negotiated format and modifier.
|
Allocate a DMA-BUF only using the negotiated format and modifier.
|
||||||
|
|
||||||
## on_event hook
|
## on_event Hook
|
||||||
|
|
||||||
This is relevant for consumers.
|
This is relevant for consumers.
|
||||||
|
|
||||||
Check the type of the dequeued buffer. If its `SPA_DATA_MemFd` or
|
Check the type of the dequeued buffer. If its `SPA_DATA_MemFd` or
|
||||||
`SPA_DATA_MemPtr` use the fallback SHM import mechanism.
|
`SPA_DATA_MemPtr` use the fallback SHM import mechanism.
|
||||||
If it's `SPA_DATA_DmaBuf`:
|
If it's `SPA_DATA_DmaBuf`
|
||||||
Get the DMA-BUF FDs (the plane count is encoded in the `n_datas` variable of the
|
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.
|
`spa_buffer` struct) and import them with the graphics API.
|
||||||
|
|
||||||
Note: Some graphics APIs have separated functions for the modifier-less case
|
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
|
(`DRM_FORMAT_MOD_INVALID`) or are omitting the modifier, since it might be used
|
||||||
for error handling.
|
for error handling.
|
||||||
|
|
||||||
## Example programs
|
## Example Programs
|
||||||
|
|
||||||
- \ref video-src-fixate.c "": \snippet{doc} video-src-fixate.c title
|
- \ref video-src-fixate.c "": \snippet{doc} video-src-fixate.c title
|
||||||
- \ref video-play-fixate.c "": \snippet{doc} video-play-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
|
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
|
to deal with DMA-BUFs. Most DMA-BUFs cannot be treated like shared memory in general
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,38 @@
|
||||||
/** \mainpage PipeWire
|
/** \mainpage PipeWire
|
||||||
|
|
||||||
PipeWire is low-level multimedia framework that provides:
|
PipeWire is low-level multimedia framework that provides:
|
||||||
- Graph based processing
|
|
||||||
- Support for out-of-process processing graphs with minimal overhead
|
- Graph based processing.
|
||||||
- Flexible and extensible media format negotiation and buffer allocation
|
- Support for out-of-process processing graphs with minimal overhead.
|
||||||
- Hard real-time capable plugins
|
- Flexible and extensible media format negotiation and buffer allocation.
|
||||||
- Very low-latency for both audio and video processing
|
- 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
|
See \ref page_overview for an overview of PipeWire and \ref page_design
|
||||||
for the design principles guiding PipeWire.
|
for the design principles guiding PipeWire.
|
||||||
|
|
||||||
### Components
|
# Components
|
||||||
|
|
||||||
PipeWire ships with the following components:
|
PipeWire ships with the following components:
|
||||||
|
|
||||||
- a \ref page_daemon that implements the IPC and graph processing
|
- 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
|
- 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 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_library to develop PipeWire applications and plugins (\ref
|
||||||
page_tutorial "tutorial").
|
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.
|
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
|
See our [Wiki](https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/home) for
|
||||||
More information on how to configure and use PipeWire.
|
More information on how to configure and use PipeWire.
|
||||||
|
|
||||||
### Resources
|
# Resources
|
||||||
|
|
||||||
- [PipeWire and AGL](https://wiki.automotivelinux.org/_media/pipewire_agl_20181206.pdf)
|
- [PipeWire and AGL](https://wiki.automotivelinux.org/_media/pipewire_agl_20181206.pdf)
|
||||||
- [LAC 2020 Paper](https://lac2020.sciencesconf.org/307881/document)
|
- [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: The Linux audio/video bus (LWN)](https://lwn.net/Articles/847412)
|
||||||
- [PipeWire Wikipedia](https://en.wikipedia.org/wiki/PipeWire)
|
- [PipeWire Wikipedia](https://en.wikipedia.org/wiki/PipeWire)
|
||||||
- [Bluetooth, PipeWire and Whatsapp calls](https://gjhenrique.com/pipewire.html)
|
- [Bluetooth, PipeWire and Whatsapp calls](https://gjhenrique.com/pipewire.html)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
/** \page page_overview Overview
|
/** \page page_overview Overview
|
||||||
|
|
||||||
PipeWire is a new low-level multimedia framework designed from scratch that
|
PipeWire is a new low-level multimedia framework designed from scratch that
|
||||||
aims to provide
|
aims to provide:
|
||||||
|
|
||||||
- graph based processing
|
- Graph based processing.
|
||||||
- support for out-of-process processing graphs with minimal overhead
|
- Support for out-of-process processing graphs with minimal overhead.
|
||||||
- flexible and extensible media format negotiation and buffer allocation
|
- Flexible and extensible media format negotiation and buffer allocation.
|
||||||
- Hard real-time capable plugins
|
- Hard real-time capable plugins.
|
||||||
- achieve very low-latency for both audio and video processing
|
- Achieve very low-latency for both audio and video processing.
|
||||||
|
|
||||||
The framework is used to build a modular daemon that can be configured to:
|
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
|
- 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
|
- A video capture server that can manage hardware video capture devices and
|
||||||
provide access to them
|
provide access to them.
|
||||||
- a central hub where video can be made available for other applications
|
- A central hub where video can be made available for other applications
|
||||||
such as the gnome-shell screencast API.
|
such as the gnome-shell screencast API.
|
||||||
|
|
||||||
|
|
||||||
## Motivation
|
# Motivation
|
||||||
|
|
||||||
Linux has no unified framework for exchanging multimedia content between
|
Linux has no unified framework for exchanging multimedia content between
|
||||||
applications or even devices. In most cases, developers realized that
|
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
|
- For video capture, we usually go directly to the hardware devices, with
|
||||||
all security implications and inflexible routing that this brings.
|
all security implications and inflexible routing that this brings.
|
||||||
- For consumer audio, we use PulseAudio to manage and mix multiple streams
|
- 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.
|
- 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
|
were designed to support the security features that are required when
|
||||||
dealing with flatpaks or other containerized applications. PipeWire
|
dealing with flatpaks or other containerized applications. PipeWire
|
||||||
aims to solve this problem and provides a unified framework to run both
|
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.
|
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.
|
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
|
As said above, modifying the object through one of these methods requires
|
||||||
the `W` permission.
|
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
|
Clients with all permissions set are referred to as "ALL" in the
|
||||||
documentation.
|
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
|
A new client is not allowed to communicate with the PipeWire daemon until
|
||||||
it has been configured with permissions.
|
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
|
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
|
certain objects. Permissions of the relevant PipeWire objects should not have
|
||||||
the `W` permission to avoid this.
|
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
|
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
|
on the node ID. By not setting the `M` bit on the other objects, this can be
|
||||||
avoided.
|
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
|
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
|
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.
|
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
|
Some applications require full access to the PipeWire graph, including
|
||||||
moving streams between nodes (by setting metadata) and modifying properties
|
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
|
# Design
|
||||||
|
|
||||||
## The PipeWire daemon
|
## The PipeWire Daemon
|
||||||
|
|
||||||
Immediately after a new client connects to the PipeWire daemon and updates
|
Immediately after a new client connects to the PipeWire daemon and updates
|
||||||
its properties, the client will be registered and made visible to other
|
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
|
sets the core permissions to `R`. This other client is usually a session
|
||||||
manager, see e.g. \ref page_session_manager.
|
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
|
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
|
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
|
property on the client object. If this property is already set, the access
|
||||||
module does nothing.
|
module does nothing.
|
||||||
|
|
||||||
If the property is not set, it will go through a set of checks to determine
|
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
|
the permissions for a client. See the \ref page_module_access documentation
|
||||||
for details, particularly on the values documented below. Depending on the
|
for details, particularly on the values documented below. Depending on the
|
||||||
value of the \ref PW_KEY_ACCESS property one the following happens:
|
value of the \ref PW_KEY_ACCESS property one the following happens:
|
||||||
|
|
||||||
- `"allowed"`, `"unrestricted"`: ALL permissions are set on the core
|
- `"allowed"`, `"unrestricted"`: ALL permissions are set on the core
|
||||||
object and the client will be able to resume.
|
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.
|
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.
|
suspended.
|
||||||
|
|
||||||
As detailed above, the client may be suspended. In that case the session
|
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
|
manager or another client is required to configure permissions on the object
|
||||||
for it to resume.
|
for it to resume.
|
||||||
|
|
||||||
## The session manager
|
## The Session Manager
|
||||||
|
|
||||||
The session manager listens for new clients to appear. It will use the
|
The session manager listens for new clients to appear. It will use the
|
||||||
\ref PW_KEY_ACCESS property to determine what to do.
|
\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
|
permission store checks or ask the user if the application is allowed
|
||||||
full access.
|
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".
|
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,
|
For details on the pipewire-media-session implementation of access control,
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,19 @@
|
||||||
|
|
||||||
This document explains how Audio is implemented.
|
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
|
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
|
When devices are plugged and unplugged the associated nodes/ports
|
||||||
need to be created and removed.
|
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
|
It must be possible to make individual audio channels available
|
||||||
as a single mono stream with a fixed format and samplerate.
|
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
|
This makes it possible to link any of the audio ports together
|
||||||
without doing conversions.
|
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
|
Applications can create ports that can connect to the audio ports
|
||||||
so that data can be provided to or consumed from them.
|
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
|
It should be possible to automatically connect an application to
|
||||||
a sink/source when it requests this.
|
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
|
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.
|
and sink so that applications are routed to them by default.
|
||||||
|
|
||||||
It should be possible to change the default audio sink/source.
|
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
|
It should be possible to move an application from one device to
|
||||||
another dynamically.
|
another dynamically.
|
||||||
|
|
||||||
### Exclusive access
|
## Exclusive Access
|
||||||
|
|
||||||
Application should be able to connect to a device in exclusive mode.
|
Application should be able to connect to a device in exclusive mode.
|
||||||
This allows the application to negotiate a specific format with the
|
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
|
This object is then responsible for controlling the \ref spa_node "SPA Nodes" that
|
||||||
provide the audio ports to interface with the device.
|
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
|
This includes the sample rate as well as the number of channels and
|
||||||
the audio format.
|
the audio format.
|
||||||
|
|
||||||
## Audio Adapter
|
## 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 internal node.
|
||||||
|
|
||||||
The function of the adapter is to convert the device native format to
|
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
|
The audio adapter can also be configured in passthrough mode when it
|
||||||
will not do any conversions but simply pass through the port information
|
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
|
Setup of the different configurations of the adapter can be done with
|
||||||
the PortConfig parameter.
|
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
|
the various audio devices. It will need to wrap them into an audio
|
||||||
adapter so that the specific configuration of the node can be
|
adapter so that the specific configuration of the node can be
|
||||||
decided by the policy mode.
|
decided by the policy mode.
|
||||||
|
|
@ -96,33 +96,32 @@ The session manager should create name and description for the
|
||||||
devices and nodes.
|
devices and nodes.
|
||||||
|
|
||||||
The session manager is responsible for assigning priorities to the
|
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.
|
need to be set.
|
||||||
|
|
||||||
The session manager might need to work with other services to gain
|
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
|
# Implementation
|
||||||
|
|
||||||
## pipewire-media-session (alsa-monitor)
|
## PipeWire Media Session (alsa-monitor)
|
||||||
|
|
||||||
PipeWire media session uses the \ref SPA_NAME_API_ALSA_ENUM_UDEV plugin
|
PipeWire media session uses the \ref SPA_NAME_API_ALSA_ENUM_UDEV plugin
|
||||||
for enumerating the ALSA devices. For each device it does:
|
for enumerating the ALSA devices. For each device it does:
|
||||||
|
|
||||||
- Try to acquire the DBus device reservation object to gain exclusive
|
- Try to acquire the DBus device reservation object to gain exclusive
|
||||||
access to the device.
|
access to the device.
|
||||||
- Create an SPA Device instance for the device and monitor this device instance.
|
- Create an SPA device instance for the device and monitor this device instance.
|
||||||
- For each Node created by the device, create an adapter with
|
- For each node created by the device, create an adapter with
|
||||||
an ALSA PCM node in the context of the PipeWire daemon.
|
an ALSA PCM node in the context of the PipeWire daemon.
|
||||||
|
|
||||||
The session manager will also create suitable names and descriptions
|
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.
|
and driver priorities.
|
||||||
|
|
||||||
The session manager has the option to add extra properties on the
|
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.
|
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
|
connections and manages devices. Clients (including the \ref
|
||||||
page_session_manager) are separate processes that talk to the daemon using the
|
page_session_manager) are separate processes that talk to the daemon using the
|
||||||
PipeWire socket (default: `$XDG_RUNTIME_DIR/pipewire-0`). This approach
|
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.
|
non-privileged clients.
|
||||||
|
|
||||||
\dot
|
\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
|
page_module_protocol_native. From PipeWire's point-of-view this module is just
|
||||||
another module.
|
another module.
|
||||||
|
|
||||||
\section sec_config Configuration Files
|
# Configuration Files
|
||||||
|
|
||||||
On startup, the daemon reads a configuration file to configure itself.
|
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
|
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
|
and array elements are appended. This makes it possible to make small custom customizations
|
||||||
or additions to the main configuration file.
|
or additions to the main configuration file.
|
||||||
|
|
||||||
The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX`
|
The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX`,
|
||||||
and `PIPEWIRE_CONFIG_NAME` can be used to specify an alternative config
|
and `PIPEWIRE_CONFIG_NAME`. Can be used to specify an alternative configuration
|
||||||
directory, subdirectory and filename, respectively.
|
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's configuration file format is JSON. In addition to true JSON
|
||||||
PipeWire also understands a more compact JSON representation where
|
PipeWire also understands a more compact JSON representation. Where
|
||||||
`"` can be omitted around strings, no trailing commas are required and
|
`"` can be omitted around strings, no trailing commas are required and
|
||||||
`:` or `=` can be used to separate object keys from their values.
|
`:` 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.
|
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
|
- **context.properties** (dictionary): These properties configure the
|
||||||
pipewire instance.
|
pipewire instance.
|
||||||
|
|
||||||
- **context.spa-libs** (dictionary): Maps plugin features with globs to a
|
- **context.spa-libs** (dictionary): Maps plugin features with globs to a
|
||||||
spa library.
|
spa library.
|
||||||
|
|
||||||
- **context.modules** (array): Each entry in the array is a dictionary with
|
- **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
|
the name of the module to load, including optional args and flags. Most
|
||||||
modules support being loaded multiple times.
|
modules support being loaded multiple times.
|
||||||
|
|
||||||
- **context.objects** (array): Each entry in the array is a dictionary con‐
|
- **context.objects** (array): Each entry in the array is a dictionary con‐
|
||||||
taining the factory to create an object from and optional extra argu‐
|
taining the factory to create an object from and optional extra argu‐
|
||||||
ments specific to that factory.
|
ments specific to that factory.
|
||||||
|
|
||||||
- **context.exec** (array): Each entry in the array is dictionary containing
|
- **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‐
|
the path of a program to execute on startup and optional args. This ar‐
|
||||||
ray usually contains an entry to start the session manager.
|
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
|
The `PIPEWIRE_DEBUG` environment variable can be used to enable
|
||||||
more debugging. This variable supports one of two formats:
|
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.
|
respective key, see below.
|
||||||
- `PIPEWIRE_DEBUG=<glob1>:<level1>,<glob2>:<level2>,...` where the globs are
|
- `PIPEWIRE_DEBUG=<glob1>:<level1>,<glob2>:<level2>,...` where the globs are
|
||||||
shell-globs to match on log topics and the levels are the respective
|
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
|
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,
|
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.
|
debugging on all modules but no messages on the foo module.
|
||||||
|
|
||||||
- `<level>` specifies the log level:
|
- `<level>` specifies the log level:
|
||||||
+ `X` or `0`: no logging is enabled
|
|
||||||
+ `E` or `1`: Error logging is enabled
|
+ `X` or `0`: No logging is enabled.
|
||||||
+ `W` or `2`: Warnings are enabled
|
+ `E` or `1`: Error logging is enabled.
|
||||||
+ `I` or `3`: Informational messages are enabled
|
+ `W` or `2`: Warnings are enabled.
|
||||||
+ `D` or `4`: Debug messages 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
|
+ `T` or `5`: Trace messages are enabled. These messages can be logged
|
||||||
from the realtime threads.
|
from the realtime threads.
|
||||||
|
|
||||||
PipeWire uses a "category.topic" naming scheme, with the following categories:
|
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
|
- `pw.*`: PipeWire internal topics.
|
||||||
"foo" module
|
- `mod.*`: Module topics, for example `mod.foo` would usually refer to the
|
||||||
- `ms.*`: media session topics
|
`foo` module.
|
||||||
- `ms.mod.*`: media session modules, for example `ms.foo` would usually refer
|
- `ms.*`: Media session topics.
|
||||||
to the "media-session-foo" module
|
- `ms.mod.*`: Media session modules, for example `ms.foo` would usually refer
|
||||||
- `conn.*`: connection-specific topics such as printing raw messages sent over
|
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
|
a communication socket. These are in a separate namespace as they are
|
||||||
usually vastly more verbose than the normal debugging topics.
|
usually vastly more verbose than the normal debugging topics.
|
||||||
This namespace must be explicitly enabled with a `conn.<glob>` glob.
|
This namespace must be explicitly enabled with a `conn.<glob>` glob.
|
||||||
|
|
||||||
|
|
||||||
The behavior of the logging can be further controlled with the following
|
The behavior of the logging can be further controlled with the following
|
||||||
environment variables:
|
environment variables:
|
||||||
- `PIPEWIRE_LOG_SYSTEMD=false`: disable logging to the systemd journal
|
|
||||||
- `PIPEWIRE_LOG=<filename>`: redirect the log to the given filename
|
- `PIPEWIRE_LOG_SYSTEMD=false`: Disable logging to the systemd journal.
|
||||||
- `PIPEWIRE_LOG_LINE=false`: don't log filename, function, and source code line
|
- `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,
|
Nodes can run inside the server process or in separate processes,
|
||||||
communicating with the server.
|
communicating with the server.
|
||||||
|
|
||||||
PipeWire was designed to
|
PipeWire was designed to:
|
||||||
|
|
||||||
- be efficient for raw video using fd passing and audio with
|
- Be efficient for raw video using fd passing and audio with
|
||||||
shared ringbuffers
|
shared ringbuffers.
|
||||||
- be able to provide/consume/process media from any process
|
- Be able to provide/consume/process media from any process.
|
||||||
- provide policy to restrict access to devices and streams
|
- Provide policy to restrict access to devices and streams.
|
||||||
- be easily extensible
|
- Be easily extensible.
|
||||||
|
|
||||||
Although an initial goal, the design is not limited to raw video
|
Although an initial goal, the design is not limited to raw video
|
||||||
only and should be able to handle compressed video and other
|
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
|
format. SPA also provides a number of helper utilities that are not available
|
||||||
in the standard C library.
|
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
|
- v4l2 device provider: Provide controlled access to v4l2 devices
|
||||||
and share one device between multiple processes.
|
and share one device between multiple processes.
|
||||||
|
- gnome-shell video provider: GNOME Shell provides a node that
|
||||||
- gnome-shell video provider: GNOME Shell provides a node that
|
gives the contents of the frame buffer for screen sharing or
|
||||||
gives the contents of the frame buffer for screen sharing or
|
screen recording.
|
||||||
screen recording.
|
- Audio server: Mix and playback multiple audio streams. The design
|
||||||
|
is more like CRAS (Chromium audio server) than PulseAudio and with
|
||||||
- audio server: Mix and playback multiple audio streams. The design
|
the added benefit that processing can be arranged in a graph.
|
||||||
is more like CRAS (Chromium audio server) than PulseAudio and with
|
- Professional audio graph processing like JACK.
|
||||||
the added benefit that processing can be arranged in a graph.
|
- Media playback backend.
|
||||||
|
|
||||||
- Pro audio graph processing like JACK.
|
|
||||||
|
|
||||||
- Media playback backend
|
|
||||||
|
|
||||||
|
|
||||||
Protocol
|
# Protocol
|
||||||
--------
|
|
||||||
|
|
||||||
The native protocol and object model is similar to
|
The native protocol and object model is similar to
|
||||||
[Wayland](https://wayland.freedesktop.org) but with custom
|
[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.
|
in the messages are more complicated and not easily expressible in XML.
|
||||||
See \ref page_module_protocol_native for details.
|
See \ref page_module_protocol_native for details.
|
||||||
|
|
||||||
|
|
||||||
Extensibility
|
# Extensibility
|
||||||
-------------
|
|
||||||
|
|
||||||
The functionality of the server is implemented and extended with modules and
|
The functionality of the server is implemented and extended with modules and
|
||||||
extensions. Modules are server side bits of logic that hook into various
|
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
|
both a client side and server side init function. New interfaces or new object
|
||||||
implementation can easily be added with modules/extensions.
|
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
|
- Protocol extensions: A client/server side API (.h) together with protocol
|
||||||
extensions and server/client side logic to implement a new object or
|
extensions and server/client side logic to implement a new object or
|
||||||
interface.
|
interface.
|
||||||
|
- A module to check security of method calls.
|
||||||
- a module to check security of method calls
|
- A module to automatically create, link or relink nodes.
|
||||||
|
- A module to suspend idle nodes.
|
||||||
- a module to automatically create, link or relink nodes
|
|
||||||
|
|
||||||
- a module to suspend idle nodes
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
/** \page page_library PipeWire Library
|
/** \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.
|
1. An implementation of a graph based media processing engine.
|
||||||
2. An asynchronous IPC mechanism to manipulate and introspect
|
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
|
There is usually a daemon that implements the global graph and
|
||||||
clients that operate on this graph.
|
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
|
follows the same design principles of objects and methods/events
|
||||||
along with how this API is presented to the user.
|
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
|
aspects of PipeWire and change the behaviour or number of
|
||||||
features dynamically.
|
features dynamically.
|
||||||
|
|
||||||
## Principles
|
|
||||||
|
# Principles
|
||||||
|
|
||||||
The PipeWire API is an object oriented asynchronous protocol.
|
The PipeWire API is an object oriented asynchronous protocol.
|
||||||
All requests and replies are method invocations on some object.
|
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
|
State about objects can be obtained by binding to them and listening
|
||||||
for state changes.
|
for state changes.
|
||||||
|
|
||||||
## Versioning
|
|
||||||
|
# Versioning
|
||||||
|
|
||||||
All interfaces have a version number. The maximum supported version
|
All interfaces have a version number. The maximum supported version
|
||||||
number of an interface is advertized in the registry global event.
|
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
|
are added. Methods or events should never be removed or changed for
|
||||||
simplicity.
|
simplicity.
|
||||||
|
|
||||||
## Proxies and resources
|
|
||||||
|
# Proxies and Resources
|
||||||
|
|
||||||
When a client connects to a PipeWire daemon, a new `struct pw_proxy`
|
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
|
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.
|
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:
|
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`
|
## struct pw_context
|
||||||
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`
|
|
||||||
|
|
||||||
The main context for PipeWire resources. It keeps track of the mainloop,
|
The main context for PipeWire resources. It keeps track of the mainloop,
|
||||||
loaded modules, the processing graph and proxies to remote PipeWire
|
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
|
The context has methods to create the various objects you can use to
|
||||||
build a server or client application.
|
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
|
A proxy to a remote PipeWire instance. This is used to send messages
|
||||||
to a remote PipeWire daemon and to receive events from it.
|
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
|
Other core methods and events are used internally for the object
|
||||||
life cycle management.
|
life cycle management.
|
||||||
|
|
||||||
### `struct pw_registry`
|
## struct pw_registry
|
||||||
|
|
||||||
A proxy to a PipeWire registry object. It emits events about the
|
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
|
available objects on the server and can be used to bind to those
|
||||||
objects in order to call methods or receive events from them.
|
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
|
A proxy to a loadable module. Modules implement functionality such
|
||||||
as provide new objects or policy.
|
as provide new objects or policy.
|
||||||
|
|
||||||
### `struct pw_factory`
|
## struct pw_factory
|
||||||
|
|
||||||
A proxy to an object that can create other objects.
|
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
|
A proxy to a device object. Device objects model a physical hardware
|
||||||
or software device in the system and can create other objects
|
or software device in the system and can create other objects
|
||||||
such as nodes or other devices.
|
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
|
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.
|
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.
|
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 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
|
a format and buffers between ports. A port can be linked to many other
|
||||||
ports and PipeWire will manage mixing and duplicating the buffers.
|
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
|
Some high level objects are implemented to make it easier to interface
|
||||||
with a PipeWire graph.
|
with a PipeWire graph.
|
||||||
|
|
||||||
### `struct pw_filter`
|
## struct pw_filter
|
||||||
|
|
||||||
A `struct pw_filter` allows you implement a processing filter that can
|
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.
|
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
|
client for the graph. It takes care of format conversion and buffer
|
||||||
sizes. It is comparable to Core Audio AudioQueue or a PulseAudio
|
sizes. It is comparable to Core Audio AudioQueue or a PulseAudio
|
||||||
stream.
|
stream.
|
||||||
|
|
||||||
|
|
||||||
## Security
|
# Security
|
||||||
|
|
||||||
With the default native protocol, clients connect to PipeWire using
|
With the default native protocol, clients connect to PipeWire using
|
||||||
a named socket. This results in a client socket that is used to
|
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
|
and data between clients. Clients can thus not look at other clients
|
||||||
data unless they can see the objects and connect to them.
|
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
|
PipeWire also exposes an API to implement the server side objects in
|
||||||
a graph.
|
a graph.
|
||||||
|
|
||||||
|
|
||||||
## Error reporting
|
# Error Reporting
|
||||||
|
|
||||||
Functions return either NULL with errno set or a negative int error
|
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
|
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
|
callback). The sequence number can be used to see which operation
|
||||||
completed.
|
completed.
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,43 @@
|
||||||
|
|
||||||
This document explains how MIDI is implemented.
|
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
|
Applications need to be able to see a port for each stream of a
|
||||||
MIDI device.
|
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
|
When devices are plugged and unplugged the associated nodes/ports
|
||||||
need to be created and removed.
|
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
|
Applications can create ports that can connect to the MIDI ports
|
||||||
so that data can be provided to or consumed from them.
|
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
|
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.
|
renderer.
|
||||||
|
|
||||||
An example of a MIDI source would be after a virtual keyboard or
|
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
|
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
|
An application should be able to connect to a MIDI source when it
|
||||||
wants to capture midi data.
|
wants to capture MIDI data.
|
||||||
|
|
||||||
|
|
||||||
# Design
|
# 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
|
are of type \ref spa_pod_sequence with the \ref spa_pod_control type set to
|
||||||
\ref SPA_CONTROL_Midi.
|
\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
|
offset against the current graph clock cycle to get sample accurate
|
||||||
midi events that can be aligned with the corresponding sample data.
|
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
|
they can be interleaved with other control message types, such as
|
||||||
property updates or OSC messages.
|
property updates or OSC messages.
|
||||||
|
|
||||||
## The PipeWire daemon
|
## The PipeWire Daemon
|
||||||
|
|
||||||
Nothing special is implemented for MIDI. Negotiation of formats
|
Nothing special is implemented for MIDI. Negotiation of formats
|
||||||
happens between `"application/control"` media types and buffers are
|
happens between `"application/control"` media types and buffers are
|
||||||
negotiated in the same way as any generic format.
|
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
|
The session manager needs to create the MIDI nodes/ports for the available
|
||||||
devices.
|
devices.
|
||||||
|
|
@ -76,10 +78,10 @@ in order to route MIDI streams to them from applications that want this.
|
||||||
|
|
||||||
# Implementation
|
# Implementation
|
||||||
|
|
||||||
## pipewire-media-session
|
## PipeWire Media Session
|
||||||
|
|
||||||
PipeWire media session uses the \ref SPA_NAME_API_ALSA_SEQ_BRIDGE plugin for
|
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.
|
MIDI client/stream.
|
||||||
|
|
||||||
The media session will check the permissions on `/dev/snd/seq` before
|
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
|
||||||
|
|
||||||
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
|
The control messages are converted to the JACK event format by
|
||||||
filtering out the \ref SPA_CONTROL_Midi types. On output ports, the JACK
|
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
|
messages so there is no information loss or need for complicated
|
||||||
conversions.
|
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
|
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
|
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*
|
$ 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
|
See the \ref page_module_example_sink and \ref page_module_example_source
|
||||||
modules for a general oveview of how modules look like.
|
modules for a general oveview of how modules look like.
|
||||||
|
|
||||||
|
|
||||||
List of known modules:
|
List of known modules:
|
||||||
|
|
||||||
- \subpage page_module_access
|
- \subpage page_module_access
|
||||||
|
|
@ -79,5 +76,4 @@ List of known modules:
|
||||||
- \subpage page_module_x11_bell
|
- \subpage page_module_x11_bell
|
||||||
- \subpage page_module_zeroconf_discover
|
- \subpage page_module_zeroconf_discover
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
/** \page page_objects_design Objects Design
|
/** \page page_objects_design Objects Design
|
||||||
|
|
||||||
This document is a design reference on the various objects that exist
|
This document is a design reference on the various objects that exist
|
||||||
in the PipeWire media and session management graphs, explaining what these
|
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
|
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.
|
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
|
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
|
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
|
A **node** is a media processing element. It consumes and/or produces buffers
|
||||||
that contain data, such as audio or video.
|
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
|
In an analogy to GStreamer, a _node_ is similar (but not equal) to a
|
||||||
GStreamer _element_.
|
GStreamer _element_.
|
||||||
|
|
||||||
### Port
|
## Port
|
||||||
|
|
||||||
A **port** is attached on a **node** and provides an interface for input
|
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.
|
or output of media on the node. A node may have multiple ports.
|
||||||
|
|
||||||
A port always has a direction, input or output:
|
A port always has a direction, input or output:
|
||||||
|
|
||||||
- Input: it allows media input into the node (in other terms, it is a _sink_)
|
- 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_)
|
- 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
|
In an analogy to GStreamer, a _port_ is similar (but not equal) to a
|
||||||
GStreamer _pad_.
|
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 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
|
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.
|
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
|
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:
|
Examples of endpoints associated with hardware on a desktop-like system:
|
||||||
- Laptop speakers
|
|
||||||
- USB webcam
|
- Laptop speakers.
|
||||||
- Bluetooth headset microphone
|
- USB webcam.
|
||||||
- Line out stereo jack port
|
- Bluetooth headset microphone.
|
||||||
|
- Line out stereo jack port.
|
||||||
|
|
||||||
Examples of endpoints associated with hardware in a car:
|
Examples of endpoints associated with hardware in a car:
|
||||||
- Speakers amplifier
|
|
||||||
- Front right seat microphone array
|
- Speakers amplifier.
|
||||||
- Rear left seat headphones
|
- Front right seat microphone array.
|
||||||
- Bluetooth phone voice gateway
|
- Rear left seat headphones.
|
||||||
- Hardware FM radio device
|
- Bluetooth phone voice gateway.
|
||||||
|
- Hardware FM radio device.
|
||||||
|
|
||||||
Examples of endpoints associated with software:
|
Examples of endpoints associated with software:
|
||||||
- Desktop screen capture source
|
|
||||||
- Media player application
|
- Desktop screen capture source.
|
||||||
- Camera application
|
- Media player application.
|
||||||
|
- Camera application.
|
||||||
|
|
||||||
In most cases an endpoint maps to a node on the media graph, but this is not
|
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.
|
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
|
it and the amplifier, so that it can apply audio policy that takes into account
|
||||||
whether the CD player is playing or not.
|
whether the CD player is playing or not.
|
||||||
|
|
||||||
#### Target
|
### Target
|
||||||
|
|
||||||
An **endpoint** may be grouping together targets that can be reached by
|
An **endpoint** may be grouping together targets that can be reached by
|
||||||
following the same route and they are mutually exclusive with each other.
|
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
|
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).
|
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
|
An **endpoint stream** is attached to an **endpoint** and represents a logical
|
||||||
path that can be taken to reach this endpoint, often associated with
|
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
|
For example, the "Speakers amplifier" endpoint in a car might have the
|
||||||
following streams:
|
following streams:
|
||||||
- _Music_: a path to play music;
|
|
||||||
the implementation will output this to all speakers, using the volume
|
- _Music_: A path to play music;
|
||||||
that has been configured for the "Music" use case
|
the implementation will output this to all speakers, using the volume
|
||||||
- _Voice_: a path to play a voice message, such as a navigation message or
|
that has been configured for the "Music" use case.
|
||||||
feedback from a voice assistant; the implementation will output this
|
- _Voice_: A path to play a voice message; such as a navigation message or
|
||||||
to the front speakers only, lowering the volume of the music (if any)
|
feedback from a voice assistant, the implementation will output this
|
||||||
on these speakers at the same time
|
to the front speakers only. Lowering the volume of the music (if any)
|
||||||
- _Emergency_: a path to play an emergency situation sound (a beep,
|
on these speakers at the same time.
|
||||||
or equivalent); the implementation will output this on all speakers,
|
- _Emergency_: A path to play an emergency situation sound (a beep,
|
||||||
increasing the volume to a factory-defined value if necessary (to ensure
|
or equivalent); the implementation will output this on all speakers.
|
||||||
that it is audible) while muting audio from all other streams at the
|
Increasing the volume to a factory defined value if necessary (to ensure
|
||||||
same time
|
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
|
In another example, a microphone that can be used for activating a voice
|
||||||
assistant might have the following streams:
|
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
|
- _Capture_: A path to capture directly from the microphone; this can be used
|
||||||
to activate the full voice recognition engine
|
by an application that listens for the assistant's wake-word in order
|
||||||
- _CaptureDelayed_: a path to capture with a constant delay (meaning that
|
to activate the full voice recognition engine.
|
||||||
starting capturing now will actually capture something that was spoken
|
- _CaptureDelayed_: A path to capture with a constant delay (meaning that
|
||||||
a little earlier); this can be used by the full voice recognition engine,
|
starting capturing now will actually capture something that was spoken
|
||||||
allowing it to start after the wake-word has been spoken while capturing
|
a little earlier); this can be used by the full voice recognition engine,
|
||||||
audio that also includes the wake-word
|
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,
|
Endpoint streams may be mutually exclusive or they may used simultaneously,
|
||||||
depending on the implementation.
|
depending on the implementation.
|
||||||
|
|
||||||
Endpoint streams may be implemented in many ways:
|
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.
|
a logical representation of media flow between the endpoints.
|
||||||
|
|
||||||
An **endpoint link** may be implemented by creating one or more _links_ in the
|
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
|
resources to enable media flow, in case the flow does not pass through the
|
||||||
media graph.
|
media graph.
|
||||||
|
|
||||||
#### Constructing
|
### Constructing
|
||||||
|
|
||||||
Constructing an **endpoint link** is done by asking the _endpoint stream_
|
Constructing an **endpoint link** is done by asking the _endpoint stream_
|
||||||
objects to prepare it. First, the source stream is asked to provide linking
|
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.
|
provided information.
|
||||||
|
|
||||||
This mechanism allows stream implementations:
|
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
|
A **device** represents a handle to an underlying API that is used to create
|
||||||
higher level objects, such as nodes, or other devices.
|
higher level objects, such as nodes, or other devices.
|
||||||
|
|
||||||
Well-known devices include:
|
Well-known devices include:
|
||||||
|
|
||||||
| Device API | Description |
|
| Device API | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| alsa.pcm.device | A handle to an ALSA card (ex. `hw:0`, `hw:1`, etc) |
|
| 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 |
|
| alsa.seq.device | A handle to an ALSA Midi device. |
|
||||||
| v4l2.device | A handle to a V4L2 device (`/dev/video0`, `/dev/video1`, etc..) |
|
| 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 |
|
| 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
|
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
|
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
|
turn the device _off_, which means that the handle is closed and not used
|
||||||
by PipeWire.
|
by PipeWire.
|
||||||
|
|
||||||
### Session
|
## Session
|
||||||
|
|
||||||
The **session** represents the session manager and can be used to expose
|
The **session** represents the session manager and can be used to expose
|
||||||
global properties or methods that affect the session management.
|
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
|
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
|
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
|
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
|
"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.
|
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
|
It is not currently defined whether it is allowed to have multiple sessions
|
||||||
or not and how the system should behave if this happens.
|
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***
|
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
|
In UCM mode, an ALSA card is represented as a PipeWire device, with the
|
||||||
available UCM verbs listed as profiles of the device.
|
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
|
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 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
|
The available UCM modifiers for each UCM device will be added as streams, plus
|
||||||
one "default" stream for accessing the device with no modifiers.
|
one "default" stream for accessing the device with no modifiers.
|
||||||
|
|
||||||
### ALSA fallback
|
## ALSA Fallback
|
||||||
|
|
||||||
| ALSA | PipeWire |
|
| ALSA | PipeWire |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
|
|
@ -268,15 +281,15 @@ one "default" stream for accessing the device with no modifiers.
|
||||||
| PCM stream | node + endpoint |
|
| PCM stream | node + endpoint |
|
||||||
|
|
||||||
In the case where UCM (or another similar mechanism) is not available,
|
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.
|
for every available PCM stream.
|
||||||
|
|
||||||
Endpoints in this case have only one "default" stream, unless they are extended
|
Endpoints in this case have only one "default" stream, unless they are extended
|
||||||
by the session manager to have software-backed streams.
|
by the session manager to have software-backed streams.
|
||||||
|
|
||||||
### V4L2
|
## V4L2
|
||||||
|
|
||||||
***FIXME***
|
***FIXME***
|
||||||
|
|
||||||
|
|
@ -284,11 +297,12 @@ by the session manager to have software-backed streams.
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| device | device + node |
|
| 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 |
|
| 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 device) | sink / source |
|
||||||
| endpoint (associated with a client) | sink-input / source-output |
|
| endpoint (associated with a client) | sink-input / source-output |
|
||||||
| endpoint target | port |
|
| 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 |
|
| PulseAudio | PipeWire |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| stream | client + node + endpoint (no targets, 1 default stream) |
|
| stream | client + node + endpoint (no targets, 1 default stream) |
|
||||||
|
|
||||||
### Jack
|
## Jack
|
||||||
|
|
||||||
Note: This section is about JACK clients connecting to PipeWire through the
|
Note: This section is about JACK clients connecting to PipeWire through the
|
||||||
JACK compatibility library. The scenario where PipeWire connects to another
|
JACK compatibility library. The scenario where PipeWire connects to another
|
||||||
JACK server as a client is out of scope here.
|
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 |
|
| PipeWire | JACK |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
|
|
@ -320,7 +334,7 @@ JACK server as a client is out of scope here.
|
||||||
| device | N/A |
|
| device | N/A |
|
||||||
| endpoint | N/A |
|
| endpoint | N/A |
|
||||||
|
|
||||||
#### Mapping JACK clients to PipeWire
|
### Mapping JACK Clients To PipeWire
|
||||||
|
|
||||||
| JACK | PipeWire |
|
| JACK | PipeWire |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
|
|
@ -328,6 +342,6 @@ JACK server as a client is out of scope here.
|
||||||
| port | port |
|
| port | port |
|
||||||
|
|
||||||
JACK clients do not create endpoints. A session manager should be JACK aware
|
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
|
client is a portal-managed client. PipeWire can detect and enforce
|
||||||
extra permission checks on the portal managed clients.
|
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)
|
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.
|
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
|
When a new client is detected, the available objects need to be
|
||||||
scanned and permissions configured for each of them.
|
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
|
Only the devices belonging to the media_roles given by the
|
||||||
portal are considered.
|
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
|
Newly created objects are made visible to a client when the client
|
||||||
is allowed to interact with it.
|
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
|
Only the devices belonging to the media_roles given by the
|
||||||
portal are considered.
|
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
|
The session manager listens to changes in the permissions of devices
|
||||||
and will remove the client permissions accordingly.
|
and will remove the client permissions accordingly.
|
||||||
|
|
@ -46,7 +47,7 @@ where these permissions can be managed.
|
||||||
|
|
||||||
# Design
|
# Design
|
||||||
|
|
||||||
## The portal
|
## The Portal
|
||||||
|
|
||||||
A sandboxed client cannot connect to PipeWire directly. Instead, it connects
|
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
|
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
|
- `"pipewire.access.portal.is_portal" = true` for the connection of the
|
||||||
portal itself (as opposed to a client managed by the portal).
|
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.
|
- `"pipewire.access.portal.media_roles"` media roles of the client.
|
||||||
Currently only `"Camera"` is defined.
|
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
|
visible, depending on the client's `media_roles` (see also \ref
|
||||||
PW_KEY_MEDIA_ROLE).
|
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`
|
processes that owns the DBus name `org.freedesktop.portal.Desktop`
|
||||||
(see the [XDG Desktop Portal](https://github.com/flatpak/xdg-desktop-portal)).
|
(see the [XDG Desktop Portal](https://github.com/flatpak/xdg-desktop-portal)).
|
||||||
|
|
||||||
|
|
@ -99,7 +100,7 @@ digraph pw {
|
||||||
}
|
}
|
||||||
\enddot
|
\enddot
|
||||||
|
|
||||||
## The client
|
## The Client
|
||||||
|
|
||||||
A client can ask the portal for a connection to the PipeWire daemon.
|
A client can ask the portal for a connection to the PipeWire daemon.
|
||||||
|
|
||||||
|
|
@ -145,7 +146,6 @@ digraph pw {
|
||||||
}
|
}
|
||||||
\enddot
|
\enddot
|
||||||
|
|
||||||
|
|
||||||
The file descriptor for this restricted connection is passed back to the
|
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
|
client which can now make use of the resources it has been permitted to
|
||||||
access.
|
access.
|
||||||
|
|
@ -169,7 +169,7 @@ digraph pw {
|
||||||
}
|
}
|
||||||
\enddot
|
\enddot
|
||||||
|
|
||||||
## The session manager
|
## The Session Manager
|
||||||
|
|
||||||
The session manager listens for new clients to appear. It will use the
|
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
|
\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
|
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
|
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
|
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.
|
decides on the links between those elements.
|
||||||
|
|
||||||
Two prominent session managers currently exist:
|
Two prominent session managers currently exist:
|
||||||
|
|
||||||
- [PipeWire Media Session](https://gitlab.freedesktop.org/pipewire/media-session), the
|
- [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
|
- [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.
|
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
|
PipeWire provides a \ref page_access "permission system" to limit client's
|
||||||
access to resources but only \ref page_module_access "basic permission
|
access to resources but only \ref page_module_access "basic permission
|
||||||
handling". The session manager is expected to decide whether clients may
|
handling". The session manager is expected to decide whether clients may
|
||||||
access specific resources.
|
access specific resources.
|
||||||
|
|
||||||
## Device management
|
|
||||||
|
# Device Management
|
||||||
|
|
||||||
PipeWire's responsibility is to open devices, however the decision on which
|
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
|
devices should be opened is the job of a session manager, including the
|
||||||
configuration of those devices.
|
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
|
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.
|
See \ref page_objects_design for details on Endpoints.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/** \page page_pipewire PipeWire Design
|
/** \page page_pipewire PipeWire Design
|
||||||
|
|
||||||
## Internals
|
# Internals
|
||||||
|
|
||||||
- \subpage page_design
|
- \subpage page_design
|
||||||
- \subpage page_audio
|
- \subpage page_audio
|
||||||
|
|
@ -11,13 +11,15 @@
|
||||||
- \subpage page_library
|
- \subpage page_library
|
||||||
- \subpage page_dma_buf
|
- \subpage page_dma_buf
|
||||||
|
|
||||||
## Components
|
|
||||||
|
# Components
|
||||||
|
|
||||||
- \subpage page_daemon
|
- \subpage page_daemon
|
||||||
- \subpage page_tools
|
- \subpage page_tools
|
||||||
- \subpage page_session_manager
|
- \subpage page_session_manager
|
||||||
|
|
||||||
## Backends
|
|
||||||
|
# Backends
|
||||||
|
|
||||||
- \subpage page_pulseaudio
|
- \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
|
This explains the mapping between alsa cards and streams and session manager
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
|
|
||||||
## ALSA Cards
|
## ALSA Cards
|
||||||
|
|
||||||
An ALSA card is exposed as a PipeWire device
|
An ALSA card is exposed as a PipeWire device.
|
||||||
|
|
||||||
## Streams
|
## 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
|
# 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.
|
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, a node is created for the associated PCM devices.
|
||||||
For each UCM verb, an Endpoint is created.
|
- For each UCM verb, an endpoint is created.
|
||||||
|
|
||||||
In a first step: For each available combination of UCM device and modifier,
|
In a first step: For each available combination of UCM device and modifier,
|
||||||
a stream is created. Streams are marked with compatible other streams.
|
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
|
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.
|
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
|
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.
|
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
|
||||||
|
|
||||||
|
The pulse ALSA backend will use the mixer controls and some probing to
|
||||||
## ALSA pulse fallback
|
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
|
# PulseAudio
|
||||||
|
|
@ -58,14 +55,14 @@ create the following nodes and endpoints
|
||||||
PulseAudio uses the session manager API to construct cards with profiles
|
PulseAudio uses the session manager API to construct cards with profiles
|
||||||
and sink/source with ports.
|
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
|
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
|
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.
|
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`?
|
> 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).
|
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:
|
Types are generally divided into two categories:
|
||||||
|
|
||||||
- String types: They identify interfaces and highlevel object types.
|
- 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.
|
performance/ease of use/low space overhead is needed.
|
||||||
|
|
||||||
The SPA type is system is statis and very simple but still allows you
|
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.
|
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
|
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
|
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
|
result code and the sequence number can later be matched to the completion
|
||||||
event.
|
event.
|
||||||
|
|
||||||
## Useful macros
|
## Useful Macros
|
||||||
|
|
||||||
SPA comes with some useful macros defined in `<spa/utils/defs.h>` and a
|
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
|
It is inspired by many other plugin APIs, mostly LV2 and
|
||||||
GStreamer. SPA provides two parts:
|
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
|
The usual approach is that PipeWire and PipeWire clients can use the
|
||||||
header-only functions to interact with the plugins. Those plugins are
|
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:
|
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 efficient both in space and in time.
|
||||||
- Very configurable and usable in many different environments. All aspects
|
- Very configurable and usable in many different environments. All aspects
|
||||||
of the plugin environment can be configured and changed, like logging,
|
of the plugin environment can be configured and changed, like logging,
|
||||||
poll loops, system calls etc.
|
poll loops, system calls, etc.
|
||||||
- Consistent API
|
- Consistent API.
|
||||||
- Extensible, new API can be added with minimal effort, existing API can be updated and versioned.
|
- 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
|
The original user of SPA is PipeWire, which uses SPA to implement the
|
||||||
low-level multimedia processing plugins, device detection, mainloops, CPU
|
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.
|
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
|
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_`
|
of utilities commonly required by C projects. SPA functions use the `spa_`
|
||||||
|
|
@ -53,7 +57,7 @@ int main(int argc, char **argv) {
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
## SPA Plugins
|
# SPA Plugins
|
||||||
|
|
||||||
SPA plugins are shared libraries (`.so` files) that can be loaded at
|
SPA plugins are shared libraries (`.so` files) that can be loaded at
|
||||||
runtime. Each library provides one or more "factories", each of which may
|
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.
|
Please see \ref page_spa_plugins for the details on how to use SPA plugins.
|
||||||
|
|
||||||
|
|
||||||
## Further details
|
# Further details
|
||||||
|
|
||||||
- \ref api_spa
|
- \ref api_spa
|
||||||
- \subpage page_spa_design
|
- \subpage page_spa_design
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,21 @@
|
||||||
\ref spa_handle "SPA plugins" are dynamically loadable objects that contain objects and interfaces that
|
\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
|
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
|
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:
|
To use a plugin, the following steps are required:
|
||||||
- **load** the shared library
|
|
||||||
- **enumerate** the available factories
|
- **Load** the shared library.
|
||||||
- **enumerate** the interfaces in each factory
|
- **Enumerate** the available factories.
|
||||||
- **instantiate** the desired interface
|
- **Enumerate** the interfaces in each factory.
|
||||||
- **use** the interface-specific functions
|
- **Instantiate** the desired interface.
|
||||||
|
- **Use** the interface-specific functions.
|
||||||
|
|
||||||
In pseudo-code, loading a logger interface looks like this:
|
In pseudo-code, loading a logger interface looks like this:
|
||||||
|
|
||||||
\code{.py}
|
\code{.py}
|
||||||
handle = dlopen("$SPA_PLUGIN_PATH/support/libspa-support.so")
|
handle = dlopen("$SPA_PLUGIN_PATH/support/libspa-support.so")
|
||||||
factory_enumeration_func = dlsym(handle, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)
|
factory_enumeration_func = dlsym(handle, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)
|
||||||
|
|
@ -71,18 +73,18 @@ factory interfaces:
|
||||||
\endverbatim
|
\endverbatim
|
||||||
|
|
||||||
|
|
||||||
## Open a plugin
|
# Open A Plugin
|
||||||
|
|
||||||
A plugin is opened with a platform specific API. In this example we use
|
A plugin is opened with a platform specific API. In this example we use
|
||||||
`dlopen()` as the method used on Linux.
|
`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
|
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.
|
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}
|
\code{.c}
|
||||||
#define SPA_PLUGIN_PATH /usr/lib64/spa-0.2/"
|
#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.
|
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:
|
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
|
We can enumerate the interfaces that we will find on this new object with
|
||||||
the `spa_handle_factory_enum_interface_info()` method. Interface types
|
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).
|
system).
|
||||||
|
|
||||||
The name of the factory is a well-known name that describes the functionality
|
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
|
Usually the name will be mapped to a specific plugin. This way an
|
||||||
alternative compatible implementation can be made in a different library.
|
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
|
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
|
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
|
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
|
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.
|
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
|
When a SPA handle is made, you can retrieve any of the interfaces that
|
||||||
it provides:
|
it provides:
|
||||||
|
|
@ -195,7 +200,7 @@ spa_log_warn(log, "Hello World!\n");
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
## Clearing an object
|
# Clearing An Object
|
||||||
|
|
||||||
After you are done with a handle you can clear it with
|
After you are done with a handle you can clear it with
|
||||||
`spa_handle_clear()` and you can unload the library with `dlclose()`.
|
`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
|
Interfaces are defined in a header file (for example see
|
||||||
`<spa/support/log.h>` for the logger API). It is a self contained
|
`<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.
|
the plugin.
|
||||||
|
|
||||||
Some interfaces also provide extra fields in the interface, like the
|
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.
|
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
|
Some interfaces will also allow you to register a callback (a hook or
|
||||||
listener) to be notified of events. This is usually when something
|
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);
|
spa_hook_remove(&listener);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
## API results
|
|
||||||
|
# API Results
|
||||||
|
|
||||||
Some interfaces provide API that gives you a list or enumeration of
|
Some interfaces provide API that gives you a list or enumeration of
|
||||||
objects/values. To avoid allocation overhead and ownership problems,
|
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
|
problems. The application can look at the pushed result and keep/copy
|
||||||
only what it wants to keep.
|
only what it wants to keep.
|
||||||
|
|
||||||
|
## Synchronous Results
|
||||||
### Synchronous results
|
|
||||||
|
|
||||||
Here is an example of enumerating parameters on a node interface.
|
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);
|
spa_hook_remove(&listener);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
## Asynchronous Results
|
||||||
### Asynchronous results
|
|
||||||
|
|
||||||
Asynchronous results are pushed to the application in the same way as
|
Asynchronous results are pushed to the application in the same way as
|
||||||
synchronous results, they are just pushed later. You can check that
|
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);
|
expected_seq = SPA_RESULT_ASYNC_SEQ(res);
|
||||||
\endcode
|
\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
|
\ref spa_pod (plain old data) is a sort of data container. It is comparable to
|
||||||
DBus Variant or LV2 Atom.
|
DBus Variant or LV2 Atom.
|
||||||
|
|
||||||
A POD can express nested structures of Objects (with properties), Vectors,
|
A POD can express nested structures of objects (with properties), vectors,
|
||||||
Arrays, sequences and various primitives types. All information in the POD
|
arrays, sequences and various primitives types. All information in the POD
|
||||||
is laid out sequentially in memory and can be written directly to
|
is laid out sequentially in memory and can be written directly to
|
||||||
storage or exchanged between processes or threads without additional
|
storage or exchanged between processes or threads without additional
|
||||||
marshalling.
|
marshalling.
|
||||||
|
|
||||||
Each POD is made of a 32 bits size followed by a 32 bits type field,
|
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.
|
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.
|
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.
|
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.
|
POD's can contain a number of basic SPA types:
|
||||||
- `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
|
|
||||||
|
|
||||||
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
|
POD's can be grouped together in these container types:
|
||||||
- `SPA_TYPE_Struct`: a collection of types and objects
|
|
||||||
- `SPA_TYPE_Object`: an object with properties
|
|
||||||
- `SPA_TYPE_Sequence`: a timed sequence of PODs
|
|
||||||
|
|
||||||
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
|
POD's can also contain some extra types:
|
||||||
- `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
|
- `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
|
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
|
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
|
estimated pretty easily and if the buffer is not large enough, an
|
||||||
appropriate error will be generated.
|
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.
|
the stack allocated buffer.
|
||||||
|
|
||||||
\code{.c}
|
\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
|
`spa_pod_builder_pop()` returns a reference to the object we completed
|
||||||
on the stack.
|
on the stack.
|
||||||
|
|
||||||
## Using varargs builder.
|
## Using varargs Builder
|
||||||
|
|
||||||
We can also use the following construct to make POD objects:
|
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));
|
SPA_POD_Float(3.1415f));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
It's not possible to use the varargs builder to make a Sequence or
|
It's not possible to use the varargs builder to make a sequence or
|
||||||
Array, use the normal builder methods for that.
|
array, use the normal builder methods for that.
|
||||||
|
|
||||||
## Making objects
|
## Making Objects
|
||||||
|
|
||||||
POD objects are containers for properties and are comparable to JSON
|
POD objects are containers for properties and are comparable to JSON
|
||||||
objects.
|
objects.
|
||||||
|
|
@ -131,7 +133,7 @@ spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
An object requires an object type (`SPA_TYPE_OBJECT_Props`) and a context
|
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
|
added to the object and their meaning. The SPA type system allows you to
|
||||||
make this connection (See the type system).
|
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));
|
SPA_PROP_frequency, SPA_POD_Float(440.0f));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
## Choice values
|
## Choice Values
|
||||||
|
|
||||||
It is possible to express ranges or enumerations of possible
|
It is possible to express ranges or enumerations of possible
|
||||||
values for properties (and to some extend structs). This is achieved
|
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
|
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
|
(of the same type). Depending on the choice type, the array values are
|
||||||
interpreted in different ways:
|
interpreted in different ways:
|
||||||
|
|
||||||
* `SPA_CHOICE_None`: no choice, first value is current
|
- `SPA_CHOICE_None`: No choice, first value is current.
|
||||||
* `SPA_CHOICE_Range`: range: default, min, max
|
- `SPA_CHOICE_Range`: Range: default, min, max.
|
||||||
* `SPA_CHOICE_Step`: range with step: default, min, max, step
|
- `SPA_CHOICE_Step`: Range with step: default, min, max, step.
|
||||||
* `SPA_CHOICE_Enum`: enum: default, alternative,...
|
- `SPA_CHOICE_Enum`: Enum: default, alternative,...
|
||||||
* `SPA_CHOICE_Flags`: bitmask of flags
|
- `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:
|
possible values for the frequency:
|
||||||
|
|
||||||
\code{.c}
|
\code{.c}
|
||||||
|
|
@ -195,8 +197,8 @@ pod = spa_pod_builder_pop(&b, &f2);
|
||||||
pod = spa_pod_builder_pop(&b, &f);
|
pod = spa_pod_builder_pop(&b, &f);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
As you can see, first push the choice as a Range, then the values. A Range
|
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
|
choice expects at least three values, the default value, minimum and maximum
|
||||||
values. There is a shortcut for this as well using varargs:
|
values. There is a shortcut for this as well using varargs:
|
||||||
|
|
||||||
\code{.c}
|
\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));
|
SPA_PROP_frequency, SPA_POD_CHOICE_RANGE_Float(440.0f, 110.0f, 880.0f));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
## Choice examples
|
## Choice Examples
|
||||||
|
|
||||||
This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
|
This is a description of a possible `SPA_TYPE_OBJECT_Format` as used when
|
||||||
enumerating allowed formats (`SPA_PARAM_EnumFormat`) in SPA objects:
|
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));
|
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
# Parsing a POD
|
|
||||||
|
|
||||||
Parsing a POD usually consists of
|
# Parsing A POD
|
||||||
|
|
||||||
* validating if raw bytes + size can contain a valid pod
|
Parsing a POD usually consists of:
|
||||||
* inspecting the type of a pod
|
|
||||||
* looping over the items in an object or struct
|
|
||||||
* getting data out of PODs.
|
|
||||||
|
|
||||||
## 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
|
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
|
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);
|
pod = spa_pod_from_data(data, maxsize, offset, size);
|
||||||
\endcode
|
\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
|
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,
|
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
|
`spa_pod_is_object_type()` can be used to check if the POD contains
|
||||||
an object of the expected type.
|
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}
|
\code{.c}
|
||||||
struct spa_pod *pod, *obj;
|
struct spa_pod *pod, *obj;
|
||||||
|
|
@ -294,7 +297,7 @@ SPA_POD_STRUCT_FOREACH(obj, pod) {
|
||||||
}
|
}
|
||||||
\endcode
|
\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.
|
below.
|
||||||
|
|
||||||
## Object Properties
|
## Object Properties
|
||||||
|
|
@ -363,7 +366,7 @@ And finally exit the container again:
|
||||||
spa_pod_parser_pop(&p, &f);
|
spa_pod_parser_pop(&p, &f);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
## Parser with variable arguments
|
## Parser With Variable Arguments
|
||||||
|
|
||||||
In most cases, parsing objects is easier with the variable argument
|
In most cases, parsing objects is easier with the variable argument
|
||||||
functions. The parse function look like the mirror image of the builder
|
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));
|
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&channels));
|
||||||
\endcode
|
\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.
|
Use the iterator for this.
|
||||||
|
|
||||||
## Choice values
|
## Choice Values
|
||||||
|
|
||||||
The parser will handle Choice values as long as they are of type
|
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
|
`none`. It will then parse the single value from the choice. When
|
||||||
dealing with other choice values, it's possible to parse the
|
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.
|
manually, if needed.
|
||||||
|
|
||||||
Here is an example of parsing the format values as a POD:
|
Here is an example of parsing the format values as a POD:
|
||||||
|
|
@ -432,9 +435,9 @@ spa_pod_parser_get_object(&p,
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
`spa_pod_get_values()` is a useful function. It returns a
|
`spa_pod_get_values()` is a useful function. It returns a
|
||||||
`struct spa_pod*` with and array of values. For normal PODs
|
`struct spa_pod*` with and array of values. For normal POD's
|
||||||
and Choice None values, it simply returns the POD and 1 value.
|
and choice none values, it simply returns the POD and one value.
|
||||||
For other Choice values it returns the Choice type and an array
|
For other choice values it returns the choice type and an array
|
||||||
of values:
|
of values:
|
||||||
|
|
||||||
\code{.c}
|
\code{.c}
|
||||||
|
|
@ -464,15 +467,16 @@ default:
|
||||||
}
|
}
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
# Filter
|
# Filter
|
||||||
|
|
||||||
Given 2 pod objects of the same type (Object, Struct, ..) one can
|
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
|
run a filter and generate a new POD that only contains values that
|
||||||
are compatible with both input pods.
|
are compatible with both input POD's.
|
||||||
|
|
||||||
This is, for example, used to find a compatible format between two ports.
|
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}
|
\code{.c}
|
||||||
pod = spa_pod_builder_add_object(&b,
|
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);
|
SPA_FORMAT_AUDIO_format, SPA_AUDIO_FORMAT_S16);
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
# POD layout
|
# POD Layout
|
||||||
|
|
||||||
Each POD has a 32 bits size field, followed by a 32 bits type field. The size
|
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.
|
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_tutorial5
|
||||||
- \subpage page_tutorial6
|
- \subpage page_tutorial6
|
||||||
|
|
||||||
## More example programs
|
|
||||||
|
# More Example Programs
|
||||||
|
|
||||||
- \ref audio-src.c "": \snippet{doc} audio-src.c title
|
- \ref audio-src.c "": \snippet{doc} audio-src.c title
|
||||||
- \ref audio-dsp-filter.c "": \snippet{doc} audio-dsp-filter.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
|
\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
|
Use this tutorial to get started and help you set up your development
|
||||||
environment.
|
environment.
|
||||||
|
|
||||||
## Initialization
|
|
||||||
|
# Initialization
|
||||||
|
|
||||||
Let get started with the simplest application.
|
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()`.
|
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
|
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
|
To compile the simple test application, copy it into a test1.c file and
|
||||||
use pkg-config to provide the required dependencies:
|
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
|
\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.
|
exit our application after we received all server objects.
|
||||||
|
|
||||||
\ref page_tutorial1 | \ref page_tutorial "Index" | \ref page_tutorial3
|
\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
|
\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
|
\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
|
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
|
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_TYPE`: The media type; like Audio, Video, MIDI.
|
||||||
* `pw_KEY_MEDIA_CATEGORY` The category, like Playback, Capture, Duplex, Monitor
|
- `PW_KEY_MEDIA_CATEGORY`: The category; like Playback, Capture, Duplex, Monitor.
|
||||||
* `PW_KEY_MEDIA_ROLE` The media role, like Movie, Music, Camera, Screen,
|
- `PW_KEY_MEDIA_ROLE`: The media role; like Movie, Music, Camera, Screen,
|
||||||
Communication, Game, Notification, DSP,
|
Communication, Game, Notification, DSP, Production, Accessibility, Test.
|
||||||
Production, Accessibility, Test
|
|
||||||
|
|
||||||
The properties are owned by the stream and freed when the stream is destroyed
|
The properties are owned by the stream and freed when the stream is destroyed
|
||||||
later.
|
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`
|
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:
|
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
|
- `PW_STREAM_FLAG_AUTOCONNECT`: Automatically connect this stream. This instructs
|
||||||
the session manager to link us to some consumer.
|
the session manager to link us to some consumer.
|
||||||
* `PW_STREAM_FLAG_MAP_BUFFERS` mmap the buffers for us so we can access the
|
- `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
|
memory. If you don't set these flags you have either work with the fd or mmap
|
||||||
either work with the fd or mmap yourself.
|
yourself.
|
||||||
* `PW_STREAM_FLAG_RT_PROCESS` Run the process function in the realtime thread.
|
- `PW_STREAM_FLAG_RT_PROCESS`: Run the process function in the realtime thread.
|
||||||
Only use this if the process function only
|
Only use this if the process function only uses functions that are realtime
|
||||||
uses functions that are realtime safe, this means
|
safe, this means no allocation or file access or any locking.
|
||||||
no allocation or file access or any locking.
|
|
||||||
|
|
||||||
And last we pass the extra parameters for our stream. Here we only have the
|
And last we pass the extra parameters for our stream. Here we only have the
|
||||||
allowed formats (`SPA_PARAM_EnumFormat`).
|
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:
|
The main program flow of the process function is:
|
||||||
|
|
||||||
* `pw_stream_dequeue_buffer()` to obtain a buffer to write into.
|
- `pw_stream_dequeue_buffer()` to obtain a buffer to write into.
|
||||||
* Get pointers in buffer memory to write to
|
- Get pointers in buffer memory to write to.
|
||||||
* write data into buffer
|
- Write data into buffer.
|
||||||
* adjust buffer with number of written bytes, offset, stride,
|
- Adjust buffer with number of written bytes, offset, stride.
|
||||||
* `pw_stream_queue_buffer()` to queue the buffer for playback.
|
- `pw_stream_queue_buffer()` to queue the buffer for playback.
|
||||||
|
|
||||||
\snippet tutorial4.c on_process
|
\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
|
\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
|
And last we pass the extra parameters for our stream. Here we only have the
|
||||||
allowed formats (`SPA_PARAM_EnumFormat`).
|
allowed formats (`SPA_PARAM_EnumFormat`).
|
||||||
|
|
||||||
|
|
||||||
Running the mainloop will start the connection and negotiation process.
|
Running the mainloop will start the connection and negotiation process.
|
||||||
First our `param_changed` event will be called with the format that was
|
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
|
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;
|
return;
|
||||||
\endcode
|
\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
|
of the param tells you what param it is. We are only interested in Format
|
||||||
param (`SPA_PARAM_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"
|
\ref page_tutorial5 | \ref page_tutorial "Index"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue