|
|
|
@ -34,20 +34,27 @@ |
|
|
|
|
#include <errno.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
#include <pipewire/pipewire.h> |
|
|
|
|
|
|
|
|
|
#include <spa/param/format-utils.h> |
|
|
|
|
#include <spa/param/video/format-utils.h> |
|
|
|
|
#include <spa/utils/defs.h> |
|
|
|
|
|
|
|
|
|
#include <pipewire/pipewire.h> |
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
#include <spa/buffer/meta.h> |
|
|
|
|
#include <spa/utils/result.h> |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define PROP_RANGE(min, max) 2, (min), (max) |
|
|
|
|
|
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct type { |
|
|
|
|
struct spa_type_media_type media_type; |
|
|
|
|
struct spa_type_media_subtype media_subtype; |
|
|
|
|
struct spa_type_format_video format_video; |
|
|
|
|
struct spa_type_video_format video_format; |
|
|
|
|
}; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
struct weston_pipewire { |
|
|
|
|
struct weston_compositor *compositor; |
|
|
|
@ -60,12 +67,19 @@ struct weston_pipewire { |
|
|
|
|
struct pw_loop *loop; |
|
|
|
|
struct wl_event_source *loop_source; |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct pw_context *context; |
|
|
|
|
#endif |
|
|
|
|
struct pw_core *core; |
|
|
|
|
struct pw_type *t; |
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct spa_hook core_listener; |
|
|
|
|
#else |
|
|
|
|
struct type type; |
|
|
|
|
|
|
|
|
|
struct pw_remote *remote; |
|
|
|
|
struct spa_hook remote_listener; |
|
|
|
|
#endif |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct pipewire_output { |
|
|
|
@ -100,6 +114,7 @@ struct pipewire_frame_data { |
|
|
|
|
struct wl_event_source *fence_sync_event_source; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
static inline void init_type(struct type *type, struct spa_type_map *map) |
|
|
|
|
{ |
|
|
|
|
spa_type_media_type_map(map, &type->media_type); |
|
|
|
@ -107,6 +122,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map) |
|
|
|
|
spa_type_format_video_map(map, &type->format_video); |
|
|
|
|
spa_type_video_format_map(map, &type->video_format); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
pipewire_debug_impl(struct weston_pipewire *pipewire, |
|
|
|
@ -141,6 +157,7 @@ pipewire_debug_impl(struct weston_pipewire *pipewire, |
|
|
|
|
free(logstr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
static void |
|
|
|
|
pipewire_debug(struct weston_pipewire *pipewire, const char *fmt, ...) |
|
|
|
|
{ |
|
|
|
@ -150,6 +167,7 @@ pipewire_debug(struct weston_pipewire *pipewire, const char *fmt, ...) |
|
|
|
|
pipewire_debug_impl(pipewire, NULL, fmt, ap); |
|
|
|
|
va_end(ap); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
pipewire_output_debug(struct pipewire_output *output, const char *fmt, ...) |
|
|
|
@ -185,7 +203,9 @@ pipewire_output_handle_frame(struct pipewire_output *output, int fd, |
|
|
|
|
const struct weston_drm_virtual_output_api *api = |
|
|
|
|
output->pipewire->virtual_output_api; |
|
|
|
|
size_t size = output->output->height * stride; |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct pw_type *t = output->pipewire->t; |
|
|
|
|
#endif |
|
|
|
|
struct pw_buffer *buffer; |
|
|
|
|
struct spa_buffer *spa_buffer; |
|
|
|
|
struct spa_meta_header *h; |
|
|
|
@ -203,7 +223,12 @@ pipewire_output_handle_frame(struct pipewire_output *output, int fd, |
|
|
|
|
|
|
|
|
|
spa_buffer = buffer->buffer; |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
if ((h = spa_buffer_find_meta_data(spa_buffer, SPA_META_Header, |
|
|
|
|
sizeof(struct spa_meta_header)))) { |
|
|
|
|
#else |
|
|
|
|
if ((h = spa_buffer_find_meta(spa_buffer, t->meta.Header))) { |
|
|
|
|
#endif |
|
|
|
|
h->pts = -1; |
|
|
|
|
h->flags = 0; |
|
|
|
|
h->seq = output->seq++; |
|
|
|
@ -375,18 +400,40 @@ pipewire_set_dpms(struct weston_output *base_output, enum dpms_enum level) |
|
|
|
|
static int |
|
|
|
|
pipewire_output_connect(struct pipewire_output *output) |
|
|
|
|
{ |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct weston_pipewire *pipewire = output->pipewire; |
|
|
|
|
struct type *type = &pipewire->type; |
|
|
|
|
#endif |
|
|
|
|
uint8_t buffer[1024]; |
|
|
|
|
struct spa_pod_builder builder = |
|
|
|
|
SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); |
|
|
|
|
const struct spa_pod *params[1]; |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct pw_type *t = pipewire->t; |
|
|
|
|
#endif |
|
|
|
|
int frame_rate = output->output->current_mode->refresh / 1000; |
|
|
|
|
int width = output->output->width; |
|
|
|
|
int height = output->output->height; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
params[0] = spa_pod_builder_add_object(&builder, |
|
|
|
|
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, |
|
|
|
|
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), |
|
|
|
|
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), |
|
|
|
|
SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_BGRx), |
|
|
|
|
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(width, height)), |
|
|
|
|
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&SPA_FRACTION (0, 1)), |
|
|
|
|
SPA_FORMAT_VIDEO_maxFramerate, |
|
|
|
|
SPA_POD_CHOICE_RANGE_Fraction(&SPA_FRACTION(frame_rate, 1), |
|
|
|
|
&SPA_FRACTION(1, 1), |
|
|
|
|
&SPA_FRACTION(frame_rate, 1))); |
|
|
|
|
|
|
|
|
|
ret = pw_stream_connect(output->stream, PW_DIRECTION_OUTPUT, SPA_ID_INVALID, |
|
|
|
|
(PW_STREAM_FLAG_DRIVER | |
|
|
|
|
PW_STREAM_FLAG_MAP_BUFFERS), |
|
|
|
|
params, 1); |
|
|
|
|
#else |
|
|
|
|
params[0] = spa_pod_builder_object(&builder, |
|
|
|
|
t->param.idEnumFormat, t->spa_format, |
|
|
|
|
"I", type->media_type.video, |
|
|
|
@ -406,6 +453,7 @@ pipewire_output_connect(struct pipewire_output *output) |
|
|
|
|
(PW_STREAM_FLAG_DRIVER | |
|
|
|
|
PW_STREAM_FLAG_MAP_BUFFERS), |
|
|
|
|
params, 1); |
|
|
|
|
#endif |
|
|
|
|
if (ret != 0) { |
|
|
|
|
weston_log("Failed to connect pipewire stream: %s", |
|
|
|
|
spa_strerror(ret)); |
|
|
|
@ -482,26 +530,42 @@ pipewire_output_stream_state_changed(void *data, enum pw_stream_state old, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
pipewire_output_stream_param_changed(void *data, uint32_t id, const struct spa_pod *format) |
|
|
|
|
#else |
|
|
|
|
pipewire_output_stream_format_changed(void *data, const struct spa_pod *format) |
|
|
|
|
#endif |
|
|
|
|
{ |
|
|
|
|
struct pipewire_output *output = data; |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct weston_pipewire *pipewire = output->pipewire; |
|
|
|
|
#endif |
|
|
|
|
uint8_t buffer[1024]; |
|
|
|
|
struct spa_pod_builder builder = |
|
|
|
|
SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); |
|
|
|
|
const struct spa_pod *params[2]; |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
struct pw_type *t = pipewire->t; |
|
|
|
|
#endif |
|
|
|
|
int32_t width, height, stride, size; |
|
|
|
|
const int bpp = 4; |
|
|
|
|
|
|
|
|
|
if (!format) { |
|
|
|
|
pipewire_output_debug(output, "format = None"); |
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
pw_stream_update_params(output->stream, NULL, 0); |
|
|
|
|
#else |
|
|
|
|
pw_stream_finish_format(output->stream, 0, NULL, 0); |
|
|
|
|
#endif |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
spa_format_video_raw_parse(format, &output->video_format); |
|
|
|
|
#else |
|
|
|
|
spa_format_video_raw_parse(format, &output->video_format, |
|
|
|
|
&pipewire->type.format_video); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
width = output->video_format.size.width; |
|
|
|
|
height = output->video_format.size.height; |
|
|
|
@ -510,6 +574,21 @@ pipewire_output_stream_format_changed(void *data, const struct spa_pod *format) |
|
|
|
|
|
|
|
|
|
pipewire_output_debug(output, "format = %dx%d", width, height); |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
params[0] = spa_pod_builder_add_object(&builder, |
|
|
|
|
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, |
|
|
|
|
SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), |
|
|
|
|
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride), |
|
|
|
|
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 2, 8), |
|
|
|
|
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16)); |
|
|
|
|
|
|
|
|
|
params[1] = spa_pod_builder_add_object(&builder, |
|
|
|
|
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, |
|
|
|
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), |
|
|
|
|
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))); |
|
|
|
|
|
|
|
|
|
pw_stream_update_params(output->stream, params, 2); |
|
|
|
|
#else |
|
|
|
|
params[0] = spa_pod_builder_object(&builder, |
|
|
|
|
t->param.idBuffers, t->param_buffers.Buffers, |
|
|
|
|
":", t->param_buffers.size, |
|
|
|
@ -527,12 +606,17 @@ pipewire_output_stream_format_changed(void *data, const struct spa_pod *format) |
|
|
|
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); |
|
|
|
|
|
|
|
|
|
pw_stream_finish_format(output->stream, 0, params, 2); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const struct pw_stream_events stream_events = { |
|
|
|
|
PW_VERSION_STREAM_EVENTS, |
|
|
|
|
.state_changed = pipewire_output_stream_state_changed, |
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
.param_changed = pipewire_output_stream_param_changed, |
|
|
|
|
#else |
|
|
|
|
.format_changed = pipewire_output_stream_format_changed, |
|
|
|
|
#endif |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct weston_output * |
|
|
|
@ -560,7 +644,11 @@ pipewire_output_create(struct weston_compositor *c, char *name) |
|
|
|
|
if (!head) |
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
output->stream = pw_stream_new(pipewire->core, name, NULL); |
|
|
|
|
#else |
|
|
|
|
output->stream = pw_stream_new(pipewire->remote, name, NULL); |
|
|
|
|
#endif |
|
|
|
|
if (!output->stream) { |
|
|
|
|
weston_log("Cannot initialize pipewire stream\n"); |
|
|
|
|
goto err; |
|
|
|
@ -704,6 +792,14 @@ weston_pipewire_loop_handler(int fd, uint32_t mask, void *data) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
static void |
|
|
|
|
weston_pipewire_error(void *data, uint32_t id, int seq, int res, |
|
|
|
|
const char *error) |
|
|
|
|
{ |
|
|
|
|
weston_log("pipewire remote error: %s\n", error); |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
static void |
|
|
|
|
weston_pipewire_state_changed(void *data, enum pw_remote_state old, |
|
|
|
|
enum pw_remote_state state, const char *error) |
|
|
|
@ -725,12 +821,20 @@ weston_pipewire_state_changed(void *data, enum pw_remote_state old, |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
static const struct pw_core_events core_events = { |
|
|
|
|
PW_VERSION_CORE_EVENTS, |
|
|
|
|
.error = weston_pipewire_error, |
|
|
|
|
}; |
|
|
|
|
#else |
|
|
|
|
static const struct pw_remote_events remote_events = { |
|
|
|
|
PW_VERSION_REMOTE_EVENTS, |
|
|
|
|
.state_changed = weston_pipewire_state_changed, |
|
|
|
|
}; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
weston_pipewire_init(struct weston_pipewire *pipewire) |
|
|
|
@ -745,10 +849,19 @@ weston_pipewire_init(struct weston_pipewire *pipewire) |
|
|
|
|
|
|
|
|
|
pw_loop_enter(pipewire->loop); |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
pipewire->context = pw_context_new(pipewire->loop, NULL, 0); |
|
|
|
|
#else |
|
|
|
|
pipewire->core = pw_core_new(pipewire->loop, NULL); |
|
|
|
|
pipewire->t = pw_core_get_type(pipewire->core); |
|
|
|
|
init_type(&pipewire->type, pipewire->t->map); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
pw_core_add_listener(pipewire->core, |
|
|
|
|
&pipewire->core_listener, |
|
|
|
|
&core_events, pipewire); |
|
|
|
|
#else |
|
|
|
|
pipewire->remote = pw_remote_new(pipewire->core, NULL, 0); |
|
|
|
|
pw_remote_add_listener(pipewire->remote, |
|
|
|
|
&pipewire->remote_listener, |
|
|
|
@ -777,6 +890,7 @@ weston_pipewire_init(struct weston_pipewire *pipewire) |
|
|
|
|
goto err; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
loop = wl_display_get_event_loop(pipewire->compositor->wl_display); |
|
|
|
|
pipewire->loop_source = |
|
|
|
@ -786,12 +900,14 @@ weston_pipewire_init(struct weston_pipewire *pipewire) |
|
|
|
|
pipewire); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
#if !PW_CHECK_VERSION(0, 2, 90) |
|
|
|
|
err: |
|
|
|
|
if (pipewire->remote) |
|
|
|
|
pw_remote_destroy(pipewire->remote); |
|
|
|
|
pw_loop_leave(pipewire->loop); |
|
|
|
|
pw_loop_destroy(pipewire->loop); |
|
|
|
|
return -1; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const struct weston_pipewire_api pipewire_api = { |
|
|
|
|