backend-pipewire: add PipeWire backend

Add a separate PipeWire backend based on the PipeWire plugin. The backend
requires PipeWire 0.3.x.

The PipeWire backend can be used as a standalone-backend backend for streaming
and composing Wayland clients to PipeWire.

The backend supports the on-demand creation of heads via the
weston_pipewire_output_api_v1. It also supports per-output pixel format
configuration via a gbm-format option.

Multiple PipeWire outputs can be created by setting the num-outputs option in
the [pipewire] section.

Co-authored-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
This commit is contained in:
Philipp Zabel 2021-05-09 16:52:36 +02:00 committed by Daniel Stone
parent bcacd9ec5a
commit ebc3a22b09
10 changed files with 1262 additions and 0 deletions

View File

@ -40,6 +40,7 @@ struct {
} backend_name_map[] = {
{ "drm", "drm-backend.so", WESTON_BACKEND_DRM },
{ "headless", "headless-backend.so", WESTON_BACKEND_HEADLESS },
{ "pipewire", "pipewire-backend.so", WESTON_BACKEND_PIPEWIRE },
{ "rdp", "rdp-backend.so", WESTON_BACKEND_RDP },
{ "vnc", "vnc-backend.so", WESTON_BACKEND_VNC },
{ "wayland", "wayland-backend.so", WESTON_BACKEND_WAYLAND },

View File

@ -60,6 +60,7 @@
#include <libweston/backend-drm.h>
#include <libweston/backend-headless.h>
#include <libweston/backend-pipewire.h>
#include <libweston/backend-rdp.h>
#include <libweston/backend-vnc.h>
#include <libweston/backend-x11.h>
@ -658,6 +659,9 @@ usage(int error_code)
#if defined(BUILD_HEADLESS_COMPOSITOR)
"\t\t\t\theadless\n"
#endif
#if defined(BUILD_PIPEWIRE_COMPOSITOR)
"\t\t\t\tpipewire\n"
#endif
#if defined(BUILD_RDP_COMPOSITOR)
"\t\t\t\trdp\n"
#endif
@ -721,6 +725,14 @@ usage(int error_code)
"\n");
#endif
#if defined(BUILD_PIPEWIRE_COMPOSITOR)
fprintf(out,
"Options for pipewire\n\n"
" --width=WIDTH\t\tWidth of desktop\n"
" --height=HEIGHT\tHeight of desktop\n"
"\n");
#endif
#if defined(BUILD_RDP_COMPOSITOR)
fprintf(out,
"Options for rdp:\n\n"
@ -3071,6 +3083,98 @@ load_headless_backend(struct weston_compositor *c,
return 0;
}
static int
pipewire_backend_output_configure(struct weston_output *output)
{
struct wet_output_config defaults = {
.width = 640,
.height = 480,
};
struct wet_compositor *compositor = to_wet_compositor(output->compositor);
struct wet_output_config *parsed_options = compositor->parsed_options;
const struct weston_pipewire_output_api *api = weston_pipewire_output_get_api(output->compositor);
struct weston_config *wc = wet_get_config(output->compositor);
struct weston_config_section *section;
char *gbm_format = NULL;
int width;
int height;
assert(parsed_options);
if (!api) {
weston_log("Cannot use weston_pipewire_output_api.\n");
return -1;
}
section = weston_config_get_section(wc, "output", "name", output->name);
parse_simple_mode(output, section, &width, &height, &defaults,
parsed_options);
if (section)
weston_config_section_get_string(section, "gbm-format",
&gbm_format, NULL);
weston_output_set_scale(output, 1);
weston_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
api->set_gbm_format(output, gbm_format);
free(gbm_format);
if (api->output_set_size(output, width, height) < 0) {
weston_log("Cannot configure output \"%s\" using weston_pipewire_output_api.\n",
output->name);
return -1;
}
weston_log("pipewire_backend_output_configure.. Done\n");
return 0;
}
static void
weston_pipewire_backend_config_init(struct weston_pipewire_backend_config *config)
{
config->base.struct_version = WESTON_PIPEWIRE_BACKEND_CONFIG_VERSION;
config->base.struct_size = sizeof(struct weston_pipewire_backend_config);
}
static int
load_pipewire_backend(struct weston_compositor *c,
int *argc, char *argv[], struct weston_config *wc,
enum weston_renderer_type renderer)
{
struct weston_pipewire_backend_config config = {{ 0, }};
struct weston_config_section *section;
struct wet_output_config *parsed_options = wet_init_parsed_options(c);
if (!parsed_options)
return -1;
weston_pipewire_backend_config_init(&config);
const struct weston_option pipewire_options[] = {
{ WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width },
{ WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height },
};
parse_options(pipewire_options, ARRAY_LENGTH(pipewire_options), argc, argv);
config.renderer = renderer;
wet_set_simple_head_configurator(c, pipewire_backend_output_configure);
section = weston_config_get_section(wc, "core", NULL, NULL);
weston_config_section_get_string(section, "gbm-format",
&config.gbm_format, NULL);
section = weston_config_get_section(wc, "pipewire", NULL, NULL);
weston_config_section_get_int(section, "num-outputs",
&config.num_outputs, 1);
return weston_compositor_load_backend(c, WESTON_BACKEND_PIPEWIRE,
&config.base);
}
static void
weston_rdp_backend_config_init(struct weston_rdp_backend_config *config)
{
@ -3608,6 +3712,9 @@ load_backend(struct weston_compositor *compositor, const char *name,
case WESTON_BACKEND_HEADLESS:
return load_headless_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_PIPEWIRE:
return load_pipewire_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_RDP:
return load_rdp_backend(compositor, argc, argv, config,
renderer);

View File

@ -0,0 +1,108 @@
/*
* Copyright © 2021-2023 Philipp Zabel <p.zabel@pengutronix.de>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_PIPEWIRE_H
#define WESTON_COMPOSITOR_PIPEWIRE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <libweston/libweston.h>
#include <libweston/plugin-registry.h>
#define WESTON_PIPEWIRE_OUTPUT_API_NAME "weston_pipewire_output_api_v1"
struct pipewire_config {
int32_t width;
int32_t height;
uint32_t framerate;
};
struct weston_pipewire_output_api {
/** Create a new PipeWire head.
*
* \param compositor The compositor instance.
* \param name Desired name for the new head
* \param config The pipewire_config of the new head.
*
* Returns 0 on success, -1 on failure.
*/
void (*head_create)(struct weston_compositor *compositor,
const char *name,
const struct pipewire_config *config);
/** Set the size of a PipeWire output to the specified width and height.
*
* If the width or height are set to -1, the size of the underlying
* PipeWire head will be used.
*
* \param output The weston output for which the size shall be set
* \param width Desired width of the output
* \param height Desired height of the output
*
* Returns 0 on success, -1 on failure.
*/
int (*output_set_size)(struct weston_output *output,
int width, int height);
/** The pixel format to be used by the output.
*
* \param output The weston output for which the pixel format is set
* \param gbm_format String representation of the pixel format
*
* Valid values for the gbm_format are:
* - NULL - The format set at backend creation time will be used;
* - "xrgb8888";
* - "rgb565";
*/
void (*set_gbm_format)(struct weston_output *output,
const char *gbm_format);
};
static inline const struct weston_pipewire_output_api *
weston_pipewire_output_get_api(struct weston_compositor *compositor)
{
const void *api;
api = weston_plugin_api_get(compositor, WESTON_PIPEWIRE_OUTPUT_API_NAME,
sizeof(struct weston_pipewire_output_api));
return (const struct weston_pipewire_output_api *)api;
}
#define WESTON_PIPEWIRE_BACKEND_CONFIG_VERSION 1
struct weston_pipewire_backend_config {
struct weston_backend_config base;
enum weston_renderer_type renderer;
char *gbm_format;
int32_t num_outputs;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_PIPEWIRE_H */

View File

@ -2252,6 +2252,7 @@ weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor
enum weston_compositor_backend {
WESTON_BACKEND_DRM,
WESTON_BACKEND_HEADLESS,
WESTON_BACKEND_PIPEWIRE,
WESTON_BACKEND_RDP,
WESTON_BACKEND_VNC,
WESTON_BACKEND_WAYLAND,

View File

@ -15,6 +15,7 @@ install_headers(
backend_drm_h = files('backend-drm.h')
backend_headless_h = files('backend-headless.h')
backend_pipewire_h = files('backend-pipewire.h')
backend_rdp_h = files('backend-rdp.h')
backend_vnc_h = files('backend-vnc.h')
backend_wayland_h = files('backend-wayland.h')

View File

@ -0,0 +1,35 @@
if not get_option('backend-pipewire')
subdir_done()
endif
user_hint = 'If you rather not build this, set \'-Dbackend-pipewire=false\'.'
config_h.set('BUILD_PIPEWIRE_COMPOSITOR', '1')
dep_libpipewire = dependency('libpipewire-0.3', required: false)
if not dep_libpipewire.found()
error('PipeWire backend requires libpipewire 0.3 which was not found. ' + user_hint)
endif
dep_libspa = dependency('libspa-0.2', required: false)
if not dep_libspa.found()
error('Pipewire plugin requires libspa 0.2 which was not found. ' + user_hint)
endif
deps_pipewire = [
dep_libweston_private,
dep_libpipewire,
dep_libspa,
dep_libdrm_headers,
]
plugin_pipewire = shared_library(
'pipewire-backend',
[ 'pipewire.c' ],
include_directories: common_inc,
dependencies: deps_pipewire,
name_prefix: '',
install: true,
install_dir: dir_module_libweston
)
env_modmap += 'pipewire-backend.so=@0@;'.format(plugin_pipewire.full_path())
install_headers(backend_pipewire_h, subdir: dir_include_libweston_install)

File diff suppressed because it is too large Load Diff

View File

@ -9024,6 +9024,7 @@ weston_compositor_get_user_data(struct weston_compositor *compositor)
static const char * const backend_map[] = {
[WESTON_BACKEND_DRM] = "drm-backend.so",
[WESTON_BACKEND_HEADLESS] = "headless-backend.so",
[WESTON_BACKEND_PIPEWIRE] = "pipewire-backend.so",
[WESTON_BACKEND_RDP] = "rdp-backend.so",
[WESTON_BACKEND_VNC] = "vnc-backend.so",
[WESTON_BACKEND_WAYLAND] = "wayland-backend.so",

View File

@ -268,6 +268,7 @@ subdir('color-lcms')
subdir('renderer-gl')
subdir('backend-drm')
subdir('backend-headless')
subdir('backend-pipewire')
subdir('backend-rdp')
subdir('backend-vnc')
subdir('backend-wayland')

View File

@ -20,6 +20,12 @@ option(
value: true,
description: 'Weston backend: headless (testing)'
)
option(
'backend-pipewire',
type: 'boolean',
value: true,
description: 'PipeWire backend: screencasting via PipeWire'
)
option(
'backend-rdp',
type: 'boolean',