2020-01-24 23:31:01 +01:00
|
|
|
#include "screencast.h"
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <spa/utils/result.h>
|
|
|
|
|
|
|
|
#include "pipewire_screencast.h"
|
|
|
|
#include "wlr_screencast.h"
|
|
|
|
#include "xdpw.h"
|
|
|
|
#include "logger.h"
|
|
|
|
|
2020-01-24 23:31:01 +01:00
|
|
|
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
|
|
|
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
|
|
|
struct xdpw_screencast_instance *cast, struct xdpw_wlr_output *out, bool with_cursor) {
|
|
|
|
cast->ctx = ctx;
|
|
|
|
cast->target_output = out;
|
|
|
|
cast->framerate = out->framerate;
|
|
|
|
cast->with_cursor = with_cursor;
|
|
|
|
cast->refcount = 1;
|
|
|
|
logprint(INFO, "xdpw: screencast instance %p has %d references", cast, cast->refcount);
|
|
|
|
wl_list_insert(&ctx->screencast_instances, &cast->link);
|
|
|
|
logprint(INFO, "xdpw: %d active screencast instances",
|
|
|
|
wl_list_length(&ctx->screencast_instances));
|
|
|
|
}
|
|
|
|
|
|
|
|
void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
|
2020-04-20 17:05:08 +02:00
|
|
|
assert(cast->refcount == 0); // Fails assert if called by screencast_finish
|
|
|
|
logprint(DEBUG, "xdpw: destroying cast instance");
|
2020-04-16 10:21:55 +02:00
|
|
|
wl_list_remove(&cast->link);
|
|
|
|
xdpw_pwr_stream_destroy(cast);
|
|
|
|
free(cast);
|
|
|
|
}
|
2020-03-10 20:46:37 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
int setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor) {
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_wlr_output *output, *tmp_o;
|
2020-01-24 23:31:01 +01:00
|
|
|
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
2020-03-13 17:43:24 +01:00
|
|
|
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s",
|
|
|
|
output->make, output->model, output->id, output->name);
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_wlr_output *out;
|
2021-03-03 10:29:56 +01:00
|
|
|
if (ctx->state->config->screencast_conf.output_name) {
|
|
|
|
out = xdpw_wlr_output_find_by_name(&ctx->output_list,
|
|
|
|
ctx->state->config->screencast_conf.output_name);
|
2020-02-19 22:55:51 +01:00
|
|
|
if (!out) {
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(ERROR, "wlroots: no such output");
|
2020-03-13 17:43:24 +01:00
|
|
|
abort();
|
2020-02-19 22:55:51 +01:00
|
|
|
}
|
|
|
|
} else {
|
2020-04-16 10:21:55 +02:00
|
|
|
out = xdpw_wlr_output_first(&ctx->output_list);
|
2020-02-19 22:55:51 +01:00
|
|
|
if (!out) {
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(ERROR, "wlroots: no output found");
|
2020-03-13 17:43:24 +01:00
|
|
|
abort();
|
2020-02-19 22:55:51 +01:00
|
|
|
}
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_screencast_instance *cast, *tmp_c;
|
|
|
|
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
|
|
|
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
|
|
|
|
cast->target_output->id,
|
|
|
|
cast->with_cursor ? "with" : "without");
|
|
|
|
|
|
|
|
if (cast->target_output->id == out->id && cast->with_cursor == with_cursor) {
|
2020-04-20 17:05:08 +02:00
|
|
|
if (cast->refcount == 0) {
|
|
|
|
logprint(DEBUG,
|
|
|
|
"xdpw: matching cast instance found, "
|
|
|
|
"but is already scheduled for destruction, skipping");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sess->screencast_instance = cast;
|
|
|
|
++cast->refcount;
|
|
|
|
}
|
|
|
|
logprint(INFO, "xdpw: screencast instance %p now has %d references",
|
|
|
|
cast, cast->refcount);
|
2020-04-16 10:21:55 +02:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
if (!sess->screencast_instance) {
|
|
|
|
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
|
|
|
|
xdpw_screencast_instance_init(ctx, sess->screencast_instance,
|
|
|
|
out, with_cursor);
|
|
|
|
}
|
|
|
|
logprint(INFO, "wlroots: output: %s",
|
|
|
|
sess->screencast_instance->target_output->name);
|
2020-03-10 20:46:37 +01:00
|
|
|
|
2020-01-24 23:31:01 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-03 16:51:31 +02:00
|
|
|
static int start_screencast(struct xdpw_screencast_instance *cast) {
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_wlr_register_cb(cast);
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-03-10 20:46:37 +01:00
|
|
|
// process at least one frame so that we know
|
|
|
|
// some of the metadata required for the pipewire
|
|
|
|
// remote state connected event
|
2020-04-16 10:21:55 +02:00
|
|
|
wl_display_dispatch(cast->ctx->state->wl_display);
|
|
|
|
wl_display_roundtrip(cast->ctx->state->wl_display);
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_pwr_stream_init(cast);
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
cast->initialized = true;
|
|
|
|
return 0;
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
|
|
|
sd_bus_error *ret_error) {
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_state *state = data;
|
|
|
|
|
2020-01-24 23:31:01 +01:00
|
|
|
int ret = 0;
|
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: create session method invoked");
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
char *request_handle, *session_handle, *app_id;
|
|
|
|
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
|
|
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
|
|
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-12-23 19:47:10 +01:00
|
|
|
char *key;
|
2020-01-24 23:31:01 +01:00
|
|
|
int innerRet = 0;
|
2020-03-13 17:43:24 +01:00
|
|
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
2020-01-24 23:31:01 +01:00
|
|
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
|
|
|
if (innerRet < 0) {
|
|
|
|
return innerRet;
|
|
|
|
}
|
|
|
|
|
2020-03-13 17:43:24 +01:00
|
|
|
if (strcmp(key, "session_handle_token") == 0) {
|
2020-12-23 19:47:10 +01:00
|
|
|
char *token;
|
2020-01-24 23:31:01 +01:00
|
|
|
sd_bus_message_read(msg, "v", "s", &token);
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: option token: %s", token);
|
2020-01-24 23:31:01 +01:00
|
|
|
} else {
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(WARN, "dbus: unknown option: %s", key);
|
2020-01-24 23:31:01 +01:00
|
|
|
sd_bus_message_skip(msg, "v");
|
|
|
|
}
|
|
|
|
|
|
|
|
innerRet = sd_bus_message_exit_container(msg);
|
|
|
|
if (innerRet < 0) {
|
|
|
|
return innerRet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sd_bus_message_exit_container(msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xdpw_request *req =
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
2020-01-24 23:31:01 +01:00
|
|
|
if (req == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xdpw_session *sess =
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
2020-01-24 23:31:01 +01:00
|
|
|
if (sess == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
sd_bus_message *reply = NULL;
|
|
|
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_send(NULL, reply, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
sd_bus_message_unref(reply);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-13 17:43:24 +01:00
|
|
|
static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
|
|
|
sd_bus_error *ret_error) {
|
2020-03-10 20:46:37 +01:00
|
|
|
struct xdpw_state *state = data;
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_screencast_context *ctx = &state->screencast;
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
int ret = 0;
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_session *sess, *tmp_s;
|
|
|
|
sd_bus_message *reply = NULL;
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: select sources method invoked");
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
// default to embedded cursor mode if not specified
|
|
|
|
bool cursor_embedded = true;
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
char *request_handle, *session_handle, *app_id;
|
|
|
|
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sd_bus_message_enter_container(msg, 'a', "{sv}");
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
|
|
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
|
|
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
2020-03-10 20:46:37 +01:00
|
|
|
|
2020-12-23 19:47:10 +01:00
|
|
|
char *key;
|
2020-01-24 23:31:01 +01:00
|
|
|
int innerRet = 0;
|
2020-03-13 17:43:24 +01:00
|
|
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
2020-01-24 23:31:01 +01:00
|
|
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
|
|
|
if (innerRet < 0) {
|
|
|
|
return innerRet;
|
|
|
|
}
|
|
|
|
|
2020-03-13 17:43:24 +01:00
|
|
|
if (strcmp(key, "multiple") == 0) {
|
2020-01-24 23:31:01 +01:00
|
|
|
bool multiple;
|
|
|
|
sd_bus_message_read(msg, "v", "b", &multiple);
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: option multiple: %x", multiple);
|
2020-03-13 17:43:24 +01:00
|
|
|
} else if (strcmp(key, "types") == 0) {
|
2020-01-24 23:31:01 +01:00
|
|
|
uint32_t mask;
|
|
|
|
sd_bus_message_read(msg, "v", "u", &mask);
|
2020-04-16 10:21:55 +02:00
|
|
|
if (mask & (1<<WINDOW)) {
|
|
|
|
logprint(INFO, "dbus: non-monitor cast requested, not replying");
|
|
|
|
return -1;
|
|
|
|
}
|
2020-03-13 17:43:24 +01:00
|
|
|
logprint(INFO, "dbus: option types:%x", mask);
|
2020-04-16 10:21:55 +02:00
|
|
|
} else if (strcmp(key, "cursor_mode") == 0) {
|
|
|
|
uint32_t cursor_mode;
|
|
|
|
sd_bus_message_read(msg, "v", "u", &cursor_mode);
|
2020-11-06 13:11:47 +01:00
|
|
|
if (cursor_mode & HIDDEN) {
|
2020-04-16 10:21:55 +02:00
|
|
|
cursor_embedded = false;
|
|
|
|
}
|
2020-11-06 13:11:47 +01:00
|
|
|
if (cursor_mode & METADATA) {
|
2020-04-16 10:21:55 +02:00
|
|
|
logprint(ERROR, "dbus: unsupported cursor mode requested, cancelling");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
|
2020-01-24 23:31:01 +01:00
|
|
|
} else {
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(WARN, "dbus: unknown option %s", key);
|
2020-01-24 23:31:01 +01:00
|
|
|
sd_bus_message_skip(msg, "v");
|
|
|
|
}
|
|
|
|
|
|
|
|
innerRet = sd_bus_message_exit_container(msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_exit_container(msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
ret = -1;
|
|
|
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
|
|
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
2020-04-20 17:05:08 +02:00
|
|
|
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
|
2020-04-16 10:21:55 +02:00
|
|
|
ret = setup_outputs(ctx, sess, cursor_embedded);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_send(NULL, reply, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sd_bus_message_unref(reply);
|
|
|
|
return 0;
|
2020-04-16 10:21:55 +02:00
|
|
|
|
|
|
|
error:
|
|
|
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
|
|
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
2020-04-20 17:05:08 +02:00
|
|
|
logprint(DEBUG, "dbus: select sources error: destroying matching session %s", sess->session_handle);
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_session_destroy(sess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_send(NULL, reply, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sd_bus_message_unref(reply);
|
|
|
|
return -1;
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|
|
|
|
|
2020-03-13 17:43:24 +01:00
|
|
|
static int method_screencast_start(sd_bus_message *msg, void *data,
|
|
|
|
sd_bus_error *ret_error) {
|
2020-03-10 20:46:37 +01:00
|
|
|
struct xdpw_state *state = data;
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
int ret = 0;
|
2020-03-10 20:46:37 +01:00
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: start method invoked");
|
2020-01-24 23:31:01 +01:00
|
|
|
|
|
|
|
char *request_handle, *session_handle, *app_id, *parent_window;
|
|
|
|
ret = sd_bus_message_read(msg, "ooss", &request_handle, &session_handle, &app_id, &parent_window);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
|
|
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
|
|
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
|
|
|
logprint(INFO, "dbus: parent_window: %s", parent_window);
|
2020-03-10 20:46:37 +01:00
|
|
|
|
2020-12-23 19:47:10 +01:00
|
|
|
char *key;
|
2020-01-24 23:31:01 +01:00
|
|
|
int innerRet = 0;
|
2020-03-13 17:43:24 +01:00
|
|
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
2020-01-24 23:31:01 +01:00
|
|
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
|
|
|
if (innerRet < 0) {
|
|
|
|
return innerRet;
|
|
|
|
}
|
2020-02-20 20:59:46 +01:00
|
|
|
logprint(WARN, "dbus: unknown option: %s", key);
|
2020-01-24 23:31:01 +01:00
|
|
|
sd_bus_message_skip(msg, "v");
|
|
|
|
innerRet = sd_bus_message_exit_container(msg);
|
|
|
|
if (innerRet < 0) {
|
|
|
|
return innerRet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = sd_bus_message_exit_container(msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
struct xdpw_screencast_instance *cast = NULL;
|
|
|
|
struct xdpw_session *sess, *tmp_s;
|
|
|
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
|
|
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
2020-04-20 17:05:08 +02:00
|
|
|
logprint(DEBUG, "dbus: start: found matching session %s", sess->session_handle);
|
2020-04-16 10:21:55 +02:00
|
|
|
cast = sess->screencast_instance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!cast) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cast->initialized) {
|
|
|
|
start_screencast(cast);
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
while (cast->node_id == 0) {
|
2020-03-10 20:46:37 +01:00
|
|
|
int ret = pw_loop_iterate(state->pw_loop, 0);
|
2020-04-16 10:21:55 +02:00
|
|
|
if (ret != 0) {
|
2020-03-13 17:43:24 +01:00
|
|
|
logprint(ERROR, "pipewire_loop_iterate failed: %s", spa_strerror(ret));
|
2020-03-10 20:46:37 +01:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
sd_bus_message *reply = NULL;
|
|
|
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-01-24 23:31:01 +01:00
|
|
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
2020-03-13 17:43:24 +01:00
|
|
|
"streams", "a(ua{sv})", 1,
|
2020-04-16 10:21:55 +02:00
|
|
|
cast->node_id, 2,
|
2020-03-13 17:43:24 +01:00
|
|
|
"position", "(ii)", 0, 0,
|
2020-04-16 10:21:55 +02:00
|
|
|
"size", "(ii)", cast->simple_frame.width, cast->simple_frame.height);
|
2020-03-13 17:43:24 +01:00
|
|
|
|
2020-01-24 23:31:01 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sd_bus_send(NULL, reply, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sd_bus_message_unref(reply);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const sd_bus_vtable screencast_vtable[] = {
|
|
|
|
SD_BUS_VTABLE_START(0),
|
2020-03-13 17:43:24 +01:00
|
|
|
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}",
|
|
|
|
method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}",
|
|
|
|
method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}",
|
|
|
|
method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
2020-04-16 10:21:55 +02:00
|
|
|
SD_BUS_PROPERTY("AvailableSourceTypes", "u", NULL,
|
|
|
|
offsetof(struct xdpw_state, screencast_source_types),
|
|
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("AvailableCursorModes", "u", NULL,
|
|
|
|
offsetof(struct xdpw_state, screencast_cursor_modes),
|
|
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("version", "u", NULL,
|
|
|
|
offsetof(struct xdpw_state, screencast_version),
|
|
|
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
2020-01-24 23:31:01 +01:00
|
|
|
SD_BUS_VTABLE_END
|
|
|
|
};
|
|
|
|
|
2021-03-03 10:29:56 +01:00
|
|
|
int xdpw_screencast_init(struct xdpw_state *state) {
|
2020-01-24 23:31:01 +01:00
|
|
|
sd_bus_slot *slot = NULL;
|
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
state->screencast = (struct xdpw_screencast_context) { 0 };
|
|
|
|
state->screencast.state = state;
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-04-16 10:21:55 +02:00
|
|
|
int err;
|
|
|
|
err = xdpw_pwr_core_connect(state);
|
|
|
|
if (err) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = xdpw_wlr_screencopy_init(state);
|
2020-01-24 23:31:01 +01:00
|
|
|
if (err) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2020-03-10 20:46:37 +01:00
|
|
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
|
|
|
screencast_vtable, state);
|
2020-01-24 23:31:01 +01:00
|
|
|
|
2020-03-13 17:43:24 +01:00
|
|
|
end:
|
2020-04-20 17:05:08 +02:00
|
|
|
// TODO: clean up pipewire
|
2020-04-16 10:21:55 +02:00
|
|
|
xdpw_wlr_screencopy_finish(&state->screencast);
|
2020-03-13 17:43:24 +01:00
|
|
|
return err;
|
2020-01-24 23:31:01 +01:00
|
|
|
}
|