Add proper event loop. Remove last threads. Update CI with pipewire.
This commit is contained in:
parent
eb229b708e
commit
c0da39f022
|
@ -5,6 +5,7 @@ packages:
|
||||||
- meson
|
- meson
|
||||||
- wayland
|
- wayland
|
||||||
- wayland-protocols
|
- wayland-protocols
|
||||||
|
- pipewire
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/emersion/xdg-desktop-portal-wlr
|
- https://github.com/emersion/xdg-desktop-portal-wlr
|
||||||
tasks:
|
tasks:
|
||||||
|
|
|
@ -53,3 +53,4 @@ dkms.conf
|
||||||
|
|
||||||
# build folder
|
# build folder
|
||||||
build/
|
build/
|
||||||
|
build-*/
|
|
@ -9,11 +9,11 @@
|
||||||
#include <spa/support/type-map.h>
|
#include <spa/support/type-map.h>
|
||||||
#include "wlr_screencast.h"
|
#include "wlr_screencast.h"
|
||||||
#include "screencast_common.h"
|
#include "screencast_common.h"
|
||||||
|
#include "xdpw.h"
|
||||||
|
|
||||||
#define BUFFERS 1
|
#define BUFFERS 1
|
||||||
#define ALIGN 16
|
#define ALIGN 16
|
||||||
|
|
||||||
void *pwr_start(void *data);
|
void *pwr_start(struct xdpw_state *state);
|
||||||
int pwr_dispatch(struct pw_loop *loop);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "pipewire_screencast.h"
|
#include "pipewire_screencast.h"
|
||||||
#include "screencast_common.h"
|
#include "screencast_common.h"
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
|
|
||||||
#define SC_MANAGER_VERSION 2
|
#define SC_MANAGER_VERSION 2
|
||||||
|
|
||||||
void wlr_frame_free(struct screencast_context *ctx);
|
struct xdpw_state;
|
||||||
int wlr_screencopy_init(struct screencast_context *ctx);
|
|
||||||
|
void wlr_frame_free(struct xdpw_state *state);
|
||||||
|
int wlr_screencopy_init(struct xdpw_state *state);
|
||||||
void wlr_screencopy_uninit(struct screencast_context *ctx);
|
void wlr_screencopy_uninit(struct screencast_context *ctx);
|
||||||
|
|
||||||
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list, const char* name);
|
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list, const char* name);
|
||||||
|
@ -30,6 +32,6 @@ struct wayland_output *wlr_output_find(struct screencast_context *ctx,
|
||||||
struct wl_output *out, uint32_t id);
|
struct wl_output *out, uint32_t id);
|
||||||
struct wayland_output *wlr_output_first(struct wl_list *output_list);
|
struct wayland_output *wlr_output_first(struct wl_list *output_list);
|
||||||
|
|
||||||
void wlr_register_cb(struct screencast_context *ctx);
|
void wlr_register_cb(struct xdpw_state *state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,6 +8,15 @@
|
||||||
#include <elogind/sd-bus.h>
|
#include <elogind/sd-bus.h>
|
||||||
#endif
|
#endif
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "screencast.h"
|
||||||
|
|
||||||
|
struct xdpw_state {
|
||||||
|
sd_bus *bus;
|
||||||
|
struct wl_display *wl_display;
|
||||||
|
struct pw_loop *pw_loop;
|
||||||
|
|
||||||
|
struct screencast_context screencast;
|
||||||
|
};
|
||||||
|
|
||||||
struct xdpw_request {
|
struct xdpw_request {
|
||||||
sd_bus_slot *slot;
|
sd_bus_slot *slot;
|
||||||
|
@ -23,8 +32,9 @@ enum {
|
||||||
PORTAL_RESPONSE_ENDED = 2
|
PORTAL_RESPONSE_ENDED = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_screenshot(sd_bus *bus);
|
int init_screenshot(struct xdpw_state *state);
|
||||||
int init_screencast(sd_bus *bus, const char *output_name, const char *forced_pixelformat);
|
int init_screencast(struct xdpw_state *state, const char *output_name,
|
||||||
|
const char *forced_pixelformat);
|
||||||
|
|
||||||
struct xdpw_request *request_create(sd_bus *bus, const char *object_path);
|
struct xdpw_request *request_create(sd_bus *bus, const char *object_path);
|
||||||
void request_destroy(struct xdpw_request *req);
|
void request_destroy(struct xdpw_request *req);
|
||||||
|
|
|
@ -22,7 +22,6 @@ add_project_arguments(cc.get_supported_arguments([
|
||||||
|
|
||||||
inc = include_directories('include')
|
inc = include_directories('include')
|
||||||
|
|
||||||
threads = dependency('threads')
|
|
||||||
rt = cc.find_library('rt')
|
rt = cc.find_library('rt')
|
||||||
pipewire = dependency('libpipewire-0.2')
|
pipewire = dependency('libpipewire-0.2')
|
||||||
spa = dependency('libspa-0.1')
|
spa = dependency('libspa-0.1')
|
||||||
|
@ -58,7 +57,6 @@ executable(
|
||||||
logind,
|
logind,
|
||||||
pipewire,
|
pipewire,
|
||||||
spa,
|
spa,
|
||||||
threads,
|
|
||||||
rt
|
rt
|
||||||
],
|
],
|
||||||
include_directories: [inc],
|
include_directories: [inc],
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <pipewire/pipewire.h>
|
||||||
#include "xdpw.h"
|
#include "xdpw.h"
|
||||||
|
|
||||||
|
enum event_loop_fd {
|
||||||
|
EVENT_LOOP_DBUS,
|
||||||
|
EVENT_LOOP_WAYLAND,
|
||||||
|
EVENT_LOOP_PIPEWIRE,
|
||||||
|
};
|
||||||
|
|
||||||
static const char service_name[] = "org.freedesktop.impl.portal.desktop.wlr";
|
static const char service_name[] = "org.freedesktop.impl.portal.desktop.wlr";
|
||||||
|
|
||||||
int xdpw_usage(FILE* stream, int rc)
|
int xdpw_usage(FILE* stream, int rc)
|
||||||
|
@ -71,8 +80,27 @@ int main(int argc, char *argv[]) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_screenshot(bus);
|
struct wl_display *wl_display = wl_display_connect(NULL);
|
||||||
init_screencast(bus, output_name, forced_pixelformat);
|
if (!wl_display) {
|
||||||
|
logprint(ERROR, "wayland: failed to connect to display");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_init(NULL, NULL);
|
||||||
|
struct pw_loop *pw_loop = pw_loop_new(NULL);
|
||||||
|
if (!pw_loop) {
|
||||||
|
logprint(ERROR, "pipewire: failed to create loop");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xdpw_state state = {
|
||||||
|
.bus = bus,
|
||||||
|
.wl_display = wl_display,
|
||||||
|
.pw_loop = pw_loop,
|
||||||
|
};
|
||||||
|
|
||||||
|
init_screenshot(&state);
|
||||||
|
init_screencast(&state, output_name, forced_pixelformat);
|
||||||
|
|
||||||
ret = sd_bus_request_name(bus, service_name, 0);
|
ret = sd_bus_request_name(bus, service_name, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -80,21 +108,63 @@ int main(int argc, char *argv[]) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pollfd pollfds[] = {
|
||||||
|
[EVENT_LOOP_DBUS] = {
|
||||||
|
.fd = sd_bus_get_fd(state.bus),
|
||||||
|
.events = POLLIN,
|
||||||
|
},
|
||||||
|
[EVENT_LOOP_WAYLAND] = {
|
||||||
|
.fd = wl_display_get_fd(state.wl_display),
|
||||||
|
.events = POLLIN,
|
||||||
|
},
|
||||||
|
[EVENT_LOOP_PIPEWIRE] = {
|
||||||
|
.fd = pw_loop_get_fd(state.pw_loop),
|
||||||
|
.events = POLLIN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = sd_bus_process(bus, NULL);
|
ret = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), -1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logprint(ERROR, "dbus: sd_bus_process failed: %s", strerror(-ret));
|
logprint(ERROR, "poll failed: %s", strerror(errno));
|
||||||
goto error;
|
goto error;
|
||||||
} else if (ret > 0) {
|
|
||||||
// We processed a request, try to process another one, right-away
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_wait(bus, (uint64_t)-1);
|
if (pollfds[EVENT_LOOP_DBUS].revents & POLLIN) {
|
||||||
if (ret < 0) {
|
logprint(TRACE, "event-loop: got dbus event");
|
||||||
logprint(ERROR, "dbus: sd_bus_wait failed: %s", strerror(-ret));
|
do {
|
||||||
goto error;
|
ret = sd_bus_process(state.bus, NULL);
|
||||||
|
} while (ret > 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
logprint(ERROR, "sd_bus_process failed: %s", strerror(-ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pollfds[EVENT_LOOP_WAYLAND].revents & POLLIN) {
|
||||||
|
logprint(TRACE, "event-loop: got wayland event");
|
||||||
|
ret = wl_display_dispatch(state.wl_display);
|
||||||
|
if (ret < 0) {
|
||||||
|
logprint(ERROR, "wl_display_dispatch failed: %s", strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollfds[EVENT_LOOP_PIPEWIRE].revents & POLLIN) {
|
||||||
|
logprint(TRACE, "event-loop: got pipewire event");
|
||||||
|
ret = pw_loop_iterate(state.pw_loop, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
logprint(ERROR, "pw_loop_iterate failed: %s", spa_strerror(ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(state.wl_display);
|
||||||
|
wl_display_flush(state.wl_display);
|
||||||
|
} while (ret > 0);
|
||||||
|
|
||||||
|
sd_bus_flush(state.bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cleanup
|
// TODO: cleanup
|
||||||
|
@ -103,5 +173,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
error:
|
error:
|
||||||
sd_bus_unref(bus);
|
sd_bus_unref(bus);
|
||||||
|
pw_loop_leave(state.pw_loop);
|
||||||
|
pw_loop_destroy(state.pw_loop);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,13 @@ static void writeFrameData(void *pwFramePointer, void *wlrFramePointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwr_on_event(void *data, uint64_t expirations) {
|
static void pwr_on_event(void *data, uint64_t expirations) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
struct pw_buffer *pw_buf;
|
struct pw_buffer *pw_buf;
|
||||||
struct spa_buffer *spa_buf;
|
struct spa_buffer *spa_buf;
|
||||||
struct spa_meta_header *h;
|
struct spa_meta_header *h;
|
||||||
struct spa_data *d;
|
struct spa_data *d;
|
||||||
|
|
||||||
if (!ctx->stream_state) {
|
|
||||||
wlr_frame_free(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logprint(TRACE, "********************");
|
logprint(TRACE, "********************");
|
||||||
logprint(TRACE, "pipewire: event fired");
|
logprint(TRACE, "pipewire: event fired");
|
||||||
|
|
||||||
|
@ -46,8 +42,10 @@ static void pwr_on_event(void *data, uint64_t expirations) {
|
||||||
|
|
||||||
spa_buf = pw_buf->buffer;
|
spa_buf = pw_buf->buffer;
|
||||||
d = spa_buf->datas;
|
d = spa_buf->datas;
|
||||||
if ((d[0].data) == NULL)
|
if ((d[0].data) == NULL) {
|
||||||
|
logprint(TRACE, "pipewire: data pointer undefined");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if ((h = spa_buffer_find_meta(spa_buf, ctx->t->meta.Header))) {
|
if ((h = spa_buffer_find_meta(spa_buf, ctx->t->meta.Header))) {
|
||||||
h->pts = -1;
|
h->pts = -1;
|
||||||
h->flags = 0;
|
h->flags = 0;
|
||||||
|
@ -77,7 +75,8 @@ static void pwr_on_event(void *data, uint64_t expirations) {
|
||||||
|
|
||||||
pw_stream_queue_buffer(ctx->stream, pw_buf);
|
pw_stream_queue_buffer(ctx->stream, pw_buf);
|
||||||
|
|
||||||
wlr_frame_free(ctx);
|
wlr_frame_free(state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwr_handle_stream_state_changed(void *data,
|
static void pwr_handle_stream_state_changed(void *data,
|
||||||
|
@ -91,9 +90,6 @@ static void pwr_handle_stream_state_changed(void *data,
|
||||||
logprint(INFO, "pipewire: node id is %d", ctx->node_id);
|
logprint(INFO, "pipewire: node id is %d", ctx->node_id);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case PW_STREAM_STATE_PAUSED:
|
|
||||||
ctx->stream_state = false;
|
|
||||||
break;
|
|
||||||
case PW_STREAM_STATE_STREAMING:
|
case PW_STREAM_STATE_STREAMING:
|
||||||
ctx->stream_state = true;
|
ctx->stream_state = true;
|
||||||
break;
|
break;
|
||||||
|
@ -141,18 +137,20 @@ static const struct pw_stream_events pwr_stream_events = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
enum pw_remote_state state,
|
enum pw_remote_state pwr_remote_state,
|
||||||
const char *error) {
|
const char *error) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
struct pw_remote *remote = ctx->remote;
|
struct pw_remote *remote = ctx->remote;
|
||||||
|
|
||||||
switch (state) {
|
switch (pwr_remote_state) {
|
||||||
case PW_REMOTE_STATE_ERROR:
|
case PW_REMOTE_STATE_ERROR:
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
logprint(ERROR, "pipewire: remote error: %s", error);
|
logprint(ERROR, "pipewire: remote error: %s", error);
|
||||||
pw_loop_leave(ctx->loop);
|
pw_loop_leave(state->pw_loop);
|
||||||
pw_loop_destroy(ctx->loop);
|
pw_loop_destroy(state->pw_loop);
|
||||||
|
ctx->err = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PW_REMOTE_STATE_CONNECTED: {
|
case PW_REMOTE_STATE_CONNECTED: {
|
||||||
|
@ -161,7 +159,7 @@ static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||||
|
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
|
|
||||||
ctx->stream = pw_stream_new(
|
ctx->stream = pw_stream_new(
|
||||||
remote, "wlr_screeencopy",
|
remote, "wlr_screeencopy",
|
||||||
|
@ -194,7 +192,7 @@ static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,18 +202,13 @@ static const struct pw_remote_events pwr_remote_events = {
|
||||||
.state_changed = pwr_handle_state_changed,
|
.state_changed = pwr_handle_state_changed,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *pwr_start(void *data) {
|
void *pwr_start(struct xdpw_state *state) {
|
||||||
|
|
||||||
struct screencast_context *ctx = data;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
pw_loop_enter(state->pw_loop);
|
||||||
pw_init(NULL, NULL);
|
|
||||||
|
|
||||||
/* create a loop */
|
|
||||||
ctx->loop = pw_loop_new(NULL);
|
|
||||||
pw_loop_enter(ctx->loop);
|
|
||||||
|
|
||||||
/* create a core, a remote, and initialize types */
|
/* create a core, a remote, and initialize types */
|
||||||
ctx->core = pw_core_new(ctx->loop, NULL);
|
ctx->core = pw_core_new(state->pw_loop, NULL);
|
||||||
ctx->t = pw_core_get_type(ctx->core);
|
ctx->t = pw_core_get_type(ctx->core);
|
||||||
ctx->remote = pw_remote_new(ctx->core, NULL, 0);
|
ctx->remote = pw_remote_new(ctx->core, NULL, 0);
|
||||||
|
|
||||||
|
@ -223,22 +216,11 @@ void *pwr_start(void *data) {
|
||||||
|
|
||||||
/* make an event to signal frame ready */
|
/* make an event to signal frame ready */
|
||||||
ctx->event =
|
ctx->event =
|
||||||
pw_loop_add_event(ctx->loop, pwr_on_event, ctx);
|
pw_loop_add_event(state->pw_loop, pwr_on_event, state);
|
||||||
|
|
||||||
pw_remote_add_listener(ctx->remote, &ctx->remote_listener, &pwr_remote_events,
|
pw_remote_add_listener(ctx->remote, &ctx->remote_listener, &pwr_remote_events,
|
||||||
ctx);
|
state);
|
||||||
pw_remote_connect(ctx->remote);
|
pw_remote_connect(ctx->remote);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pwr_dispatch(struct pw_loop *loop) {
|
|
||||||
|
|
||||||
logprint(TRACE, "pipewire: dispatch");
|
|
||||||
int res;
|
|
||||||
res = pw_loop_iterate(loop, 0);
|
|
||||||
if (res < 0)
|
|
||||||
logprint(ERROR, "pw_loop_iterate failed: %s", spa_strerror(res));
|
|
||||||
return res;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include "screencast.h"
|
#include "screencast.h"
|
||||||
|
|
||||||
static struct screencast_context ctx;
|
|
||||||
|
|
||||||
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
||||||
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
|
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
|
||||||
|
|
||||||
int setup_outputs(struct screencast_context *ctx) {
|
int setup_outputs(struct xdpw_state *state) {
|
||||||
|
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
struct wayland_output *output, *tmp_o;
|
struct wayland_output *output, *tmp_o;
|
||||||
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
||||||
|
@ -32,7 +32,8 @@ int setup_outputs(struct screencast_context *ctx) {
|
||||||
ctx->framerate = out->framerate;
|
ctx->framerate = out->framerate;
|
||||||
ctx->with_cursor = true;
|
ctx->with_cursor = true;
|
||||||
|
|
||||||
logprint(INFO, "wlroots: wl_display fd: %d", wl_display_get_fd(ctx->display));
|
logprint(INFO, "wlroots: output: %s", ctx->target_output->name);
|
||||||
|
logprint(INFO, "wlroots: wl_display fd: %d", wl_display_get_fd(state->wl_display));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -40,14 +41,17 @@ int setup_outputs(struct screencast_context *ctx) {
|
||||||
|
|
||||||
void *start_screencast(void *data){
|
void *start_screencast(void *data){
|
||||||
|
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
wlr_register_cb(ctx);
|
wlr_register_cb(state);
|
||||||
|
|
||||||
pwr_start((void *) ctx);
|
// process at least one frame so that we know
|
||||||
|
// some of the metadata required for the pipewire
|
||||||
|
// remote state connected event
|
||||||
|
wl_display_dispatch(state->wl_display);
|
||||||
|
wl_display_roundtrip(state->wl_display);
|
||||||
|
|
||||||
/* Run capture */
|
pwr_start(state);
|
||||||
while (wl_display_dispatch(ctx->display) != -1 && !ctx->err && !ctx->quit);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -140,13 +144,13 @@ static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
|
|
||||||
static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||||
|
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
logprint(INFO, "dbus: select sources method invoked");
|
logprint(INFO, "dbus: select sources method invoked");
|
||||||
|
|
||||||
setup_outputs(ctx);
|
setup_outputs(state);
|
||||||
|
|
||||||
char *request_handle, *session_handle, *app_id;
|
char *request_handle, *session_handle, *app_id;
|
||||||
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
||||||
|
@ -217,14 +221,14 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_
|
||||||
|
|
||||||
static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||||
|
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
logprint(INFO, "dbus: start method invoked");
|
logprint(INFO, "dbus: start method invoked");
|
||||||
|
|
||||||
pthread_t screencast_thread;
|
start_screencast(state);
|
||||||
pthread_create(&screencast_thread, NULL, start_screencast, ctx);
|
|
||||||
|
|
||||||
char *request_handle, *session_handle, *app_id, *parent_window;
|
char *request_handle, *session_handle, *app_id, *parent_window;
|
||||||
ret = sd_bus_message_read(msg, "ooss", &request_handle, &session_handle, &app_id, &parent_window);
|
ret = sd_bus_message_read(msg, "ooss", &request_handle, &session_handle, &app_id, &parent_window);
|
||||||
|
@ -271,7 +275,13 @@ static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(ctx->node_id == 0);
|
while(ctx->node_id == 0){
|
||||||
|
int ret = pw_loop_iterate(state->pw_loop, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
logprint(ERROR, "pipewire_loop_iterate failed: %s",
|
||||||
|
spa_strerror(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
||||||
"streams", "a(ua{sv})", 1,
|
"streams", "a(ua{sv})", 1,
|
||||||
|
@ -288,9 +298,6 @@ static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error
|
||||||
}
|
}
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
|
|
||||||
while (wl_display_dispatch(ctx->display) != -1 && !ctx->err && !ctx->quit);
|
|
||||||
pthread_join(screencast_thread, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,25 +309,26 @@ static const sd_bus_vtable screencast_vtable[] = {
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_screencast(sd_bus *bus, const char *output_name, const char *forced_pixelformat) {
|
int init_screencast(struct xdpw_state *state, const char *output_name, const char *forced_pixelformat) {
|
||||||
// TODO: cleanup
|
// TODO: cleanup
|
||||||
sd_bus_slot *slot = NULL;
|
sd_bus_slot *slot = NULL;
|
||||||
|
|
||||||
ctx.forced_pixelformat = forced_pixelformat;
|
state->screencast = (struct screencast_context) { 0 };
|
||||||
ctx.output_name = output_name;
|
state->screencast.forced_pixelformat = forced_pixelformat;
|
||||||
ctx.simple_frame = (struct simple_frame){0};
|
state->screencast.output_name = output_name;
|
||||||
ctx.simple_frame.damage = &(struct damage){0};
|
state->screencast.simple_frame = (struct simple_frame){0};
|
||||||
|
state->screencast.simple_frame.damage = &(struct damage){0};
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
err = wlr_screencopy_init(&ctx);
|
err = wlr_screencopy_init(state);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_bus_add_object_vtable(bus, &slot, object_path, interface_name,
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
||||||
screencast_vtable, &ctx);
|
screencast_vtable, state);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
wlr_screencopy_uninit(&ctx);
|
wlr_screencopy_uninit(&state->screencast);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#include "wlr_screencast.h"
|
#include "wlr_screencast.h"
|
||||||
|
#include "xdpw.h"
|
||||||
|
|
||||||
void wlr_frame_free(struct screencast_context *ctx) {
|
void wlr_frame_free(struct xdpw_state *state) {
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_destroy(ctx->wlr_frame);
|
zwlr_screencopy_frame_v1_destroy(state->screencast.wlr_frame);
|
||||||
munmap(ctx->simple_frame.data, ctx->simple_frame.size);
|
munmap(state->screencast.simple_frame.data, state->screencast.simple_frame.size);
|
||||||
wl_buffer_destroy(ctx->simple_frame.buffer);
|
wl_buffer_destroy(state->screencast.simple_frame.buffer);
|
||||||
logprint(TRACE, "wlroots: frame destroyed");
|
logprint(TRACE, "wlroots: frame destroyed");
|
||||||
|
|
||||||
|
if(!state->screencast.quit && !state->screencast.err){
|
||||||
|
wlr_register_cb(state);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
|
@ -24,9 +29,8 @@ static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
shm_unlink(shm_name);
|
shm_unlink(shm_name);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
while ((ret = ftruncate(fd, size)) == EINTR) {
|
while ((ret = ftruncate(fd, size)) == EINTR);
|
||||||
// No-op
|
|
||||||
}
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
logprint(ERROR, "wlroots: ftruncate failed");
|
logprint(ERROR, "wlroots: ftruncate failed");
|
||||||
|
@ -53,7 +57,8 @@ static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t format, uint32_t width, uint32_t height,
|
uint32_t format, uint32_t width, uint32_t height,
|
||||||
uint32_t stride) {
|
uint32_t stride) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: buffer event handler");
|
logprint(TRACE, "wlroots: buffer event handler");
|
||||||
ctx->wlr_frame = frame;
|
ctx->wlr_frame = frame;
|
||||||
|
@ -70,11 +75,13 @@ static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_copy_with_damage(frame, ctx->simple_frame.buffer);
|
zwlr_screencopy_frame_v1_copy_with_damage(frame, ctx->simple_frame.buffer);
|
||||||
|
logprint(TRACE, "wlroots: frame copied");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: flags event handler");
|
logprint(TRACE, "wlroots: flags event handler");
|
||||||
ctx->simple_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
ctx->simple_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||||
|
@ -84,37 +91,41 @@ static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
||||||
uint32_t tv_nsec) {
|
uint32_t tv_nsec) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: ready event handler");
|
logprint(TRACE, "wlroots: ready event handler");
|
||||||
|
|
||||||
ctx->simple_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
|
ctx->simple_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
|
||||||
ctx->simple_frame.tv_nsec = tv_nsec;
|
ctx->simple_frame.tv_nsec = tv_nsec;
|
||||||
|
|
||||||
if (!ctx->quit && !ctx->err) {
|
if (!ctx->quit && !ctx->err && ctx->stream_state) {
|
||||||
pw_loop_signal_event(ctx->loop, ctx->event);
|
pw_loop_signal_event(state->pw_loop, ctx->event);
|
||||||
|
return ;
|
||||||
if(ctx->loop)
|
|
||||||
if(pwr_dispatch(ctx->loop) < 0) ctx->err = true;
|
|
||||||
|
|
||||||
wlr_register_cb(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_frame_free(state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_failed(void *data,
|
static void wlr_frame_failed(void *data,
|
||||||
struct zwlr_screencopy_frame_v1 *frame) {
|
struct zwlr_screencopy_frame_v1 *frame) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: failed event handler");
|
logprint(TRACE, "wlroots: failed event handler");
|
||||||
|
|
||||||
wlr_frame_free(ctx);
|
|
||||||
ctx->err = true;
|
ctx->err = true;
|
||||||
|
|
||||||
|
wlr_frame_free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t x, uint32_t y, uint32_t width,
|
uint32_t x, uint32_t y, uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
struct screencast_context *ctx = data;
|
struct xdpw_state *state = data;
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
logprint(TRACE, "wlroots: damage event handler");
|
||||||
|
|
||||||
ctx->simple_frame.damage->x = x;
|
ctx->simple_frame.damage->x = x;
|
||||||
ctx->simple_frame.damage->y = y;
|
ctx->simple_frame.damage->y = y;
|
||||||
|
@ -130,12 +141,15 @@ static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
||||||
.damage = wlr_frame_damage,
|
.damage = wlr_frame_damage,
|
||||||
};
|
};
|
||||||
|
|
||||||
void wlr_register_cb(struct screencast_context *ctx) {
|
void wlr_register_cb(struct xdpw_state *state) {
|
||||||
|
|
||||||
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
ctx->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
ctx->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
||||||
ctx->screencopy_manager, ctx->with_cursor, ctx->target_output->output);
|
ctx->screencopy_manager, ctx->with_cursor, ctx->target_output->output);
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_add_listener(ctx->frame_callback,
|
zwlr_screencopy_frame_v1_add_listener(ctx->frame_callback,
|
||||||
&wlr_frame_listener, ctx);
|
&wlr_frame_listener, state);
|
||||||
logprint(TRACE, "wlroots: callbacks registered");
|
logprint(TRACE, "wlroots: callbacks registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,30 +299,29 @@ static const struct wl_registry_listener wlr_registry_listener = {
|
||||||
.global_remove = wlr_registry_handle_remove,
|
.global_remove = wlr_registry_handle_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
int wlr_screencopy_init(struct screencast_context *ctx) {
|
int wlr_screencopy_init(struct xdpw_state *state) {
|
||||||
// connect to wayland display WAYLAND_DISPLAY or 'wayland-0' if not set
|
struct screencast_context *ctx = &state->screencast;
|
||||||
ctx->display = wl_display_connect(NULL);
|
|
||||||
if (!ctx->display) {
|
|
||||||
logprint(ERROR, "Failed to connect to display!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve list of outputs
|
// retrieve list of outputs
|
||||||
wl_list_init(&ctx->output_list);
|
wl_list_init(&ctx->output_list);
|
||||||
|
|
||||||
// retrieve registry
|
// retrieve registry
|
||||||
ctx->registry = wl_display_get_registry(ctx->display);
|
ctx->registry = wl_display_get_registry(state->wl_display);
|
||||||
wl_registry_add_listener(ctx->registry, &wlr_registry_listener, ctx);
|
wl_registry_add_listener(ctx->registry, &wlr_registry_listener, ctx);
|
||||||
|
|
||||||
wl_display_dispatch(ctx->display);
|
wl_display_dispatch(state->wl_display);
|
||||||
wl_display_roundtrip(ctx->display);
|
wl_display_roundtrip(state->wl_display);
|
||||||
|
|
||||||
|
logprint(TRACE, "wayland: registry listeners run");
|
||||||
|
|
||||||
wlr_init_xdg_outputs(ctx);
|
wlr_init_xdg_outputs(ctx);
|
||||||
|
|
||||||
wl_display_dispatch(ctx->display);
|
wl_display_dispatch(state->wl_display);
|
||||||
wl_display_roundtrip(ctx->display);
|
wl_display_roundtrip(state->wl_display);
|
||||||
|
|
||||||
// make sure our wlroots supports screencopy protocol
|
logprint(TRACE, "wayland: xdg output listeners run");
|
||||||
|
|
||||||
|
// make sure our wlroots supports shm protocol
|
||||||
if (!ctx->shm) {
|
if (!ctx->shm) {
|
||||||
logprint(ERROR, "Compositor doesn't support %s!", "wl_shm");
|
logprint(ERROR, "Compositor doesn't support %s!", "wl_shm");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -90,9 +90,9 @@ static const sd_bus_vtable screenshot_vtable[] = {
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_screenshot(sd_bus *bus) {
|
int init_screenshot(struct xdpw_state *state) {
|
||||||
// TODO: cleanup
|
// TODO: cleanup
|
||||||
sd_bus_slot *slot = NULL;
|
sd_bus_slot *slot = NULL;
|
||||||
return sd_bus_add_object_vtable(bus, &slot, object_path, interface_name,
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
||||||
screenshot_vtable, NULL);
|
screenshot_vtable, NULL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue