dbus websocket: add screen capture http request [1/1]
PD#SWPL-184678
Problem:
add screen capture http request
Solution:
add screen capture http request
Verify:
local
Change-Id: I5eaca13de273d601abf8dab139df515ce8f57731
Signed-off-by: Daogao Xu <daogao.xu@amlogic.com>
diff --git a/aml_dbus_ws_br/jsonrpc-dbus.c b/aml_dbus_ws_br/jsonrpc-dbus.c
index 11a756e..bd9c98e 100644
--- a/aml_dbus_ws_br/jsonrpc-dbus.c
+++ b/aml_dbus_ws_br/jsonrpc-dbus.c
@@ -81,6 +81,8 @@
static int dbus_sig_get_len(const char *sig) {
char buf[64], s = 0, pos = 1, ch = *sig;
+ if (*sig == '\0')
+ return 0;
do {
if ((ch == 'a' || ch == '(' || ch == '{') && s < sizeof(buf)) {
buf[s++] = ch;
diff --git a/aml_dbus_ws_br/main.c b/aml_dbus_ws_br/main.c
index d58099d..b564248 100644
--- a/aml_dbus_ws_br/main.c
+++ b/aml_dbus_ws_br/main.c
@@ -33,8 +33,12 @@
#include <stdio.h>
#include <string.h>
#include <systemd/sd-bus.h>
+#include <fcntl.h> /* Obtain O_* constant definitions */
+#include <unistd.h>
+
#define WS_PROTOCOL_NAME "ambus-ws-br"
+#define WS_PROTOCOL_EXT "http-ext"
struct json_msg_buf {
struct json_msg_buf *next;
@@ -197,10 +201,118 @@
static void sul_timer(struct lws_sorted_usec_list *sul) { dbus_process(); }
+struct http_capture_request {
+ struct lws *wsi, *wsi_pipe;
+ sd_bus_slot *slot;
+ int fds[2];
+ int len;
+};
+
+static int call_capture_screen_reply(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ struct http_capture_request *pss = (struct http_capture_request *)userdata;
+ int ret = 0;
+ close(pss->fds[1]);
+ if (sd_bus_message_is_method_error(m, NULL)) {
+ lwsl_warn("capture fail %s\n", sd_bus_message_get_error(m)->message);
+ ret = lws_return_http_status(pss->wsi, HTTP_STATUS_SERVICE_UNAVAILABLE, sd_bus_message_get_error(m)->message);
+ } else {
+ fcntl(pss->fds[0], F_SETFL, fcntl(pss->fds[0], F_GETFL, 0) | O_NONBLOCK);
+ lws_sock_file_fd_type sock;
+ sock.sockfd = pss->fds[0];
+ pss->wsi_pipe = lws_adopt_descriptor_vhost(data.vhost, LWS_ADOPT_RAW_FILE_DESC, sock, WS_PROTOCOL_EXT, NULL);
+ if (pss->wsi_pipe == NULL) {
+ lwsl_warn("%s: foreign socket adoption failed\n", __func__);
+ ret = lws_return_http_status(pss->wsi, HTTP_STATUS_SERVICE_UNAVAILABLE, "foreign socket adoption failed");
+ } else {
+ uint8_t buf[4096], *p = buf, *end = &buf[sizeof(buf) - 1];
+ lws_set_opaque_user_data(pss->wsi_pipe, pss);
+ ret =
+ lws_add_http_common_headers(pss->wsi, HTTP_STATUS_OK, "image/jpeg", LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end) ||
+ lws_finalize_write_http_header(pss->wsi, buf, &p, end);
+ goto done;
+ }
+ }
+ ret = ret || lws_http_transaction_completed(pss->wsi);
+done:
+ if (ret)
+ lwsl_warn("http result %d\n", ret);
+ return 0;
+}
+
+static int callback_http_ext(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
+ struct http_capture_request *pss = (struct http_capture_request *)user;
+ lwsl_info("callback_http_ext %s reason:%d\n", lws_wsi_tag(wsi), reason);
+ switch (reason) {
+ case LWS_CALLBACK_HTTP: {
+ pss->wsi = wsi;
+ uint8_t buf[32];
+ if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) /* not a GET */
+ break;
+ int width = lws_get_urlarg_by_name_safe(wsi, "width", buf, sizeof(buf) - 1) > 0 ? atoi(buf) : 1280;
+ int height = lws_get_urlarg_by_name_safe(wsi, "height", buf, sizeof(buf) - 1) > 0 ? atoi(buf) : 720;
+ int type = lws_get_urlarg_by_name_safe(wsi, "type", buf, sizeof(buf) - 1) > 0 ? atoi(buf) : 2;
+ if (pipe2(pss->fds, O_CLOEXEC)) {
+ lwsl_warn("%s: call pipe fail %d %s\n", __func__, errno, strerror(errno));
+ return 1;
+ }
+ pss->len = 0;
+ int res = sd_bus_call_method_async(data.bus, &pss->slot, "amlogic.yocto.plf1", "/amlogic/yocto/ScreenCapture1",
+ "amlogic.yocto.ScreenCapture1", "start", call_capture_screen_reply, pss, "hiii",
+ pss->fds[1], width, height, type);
+ if (res < 0) {
+ lwsl_warn("%s: call amlogic.yocto.ScreenCapture1 start fail %d\n", __func__, res);
+ return 1;
+ }
+ return 0;
+ } break;
+ case LWS_CALLBACK_HTTP_WRITEABLE: {
+ int complete = 0;
+ if (pss->wsi_pipe) {
+ uint8_t buf[LWS_PRE + 4096], *start = &buf[LWS_PRE];
+ int len = read(pss->fds[0], start, sizeof(buf) - LWS_PRE);
+ lwsl_info("callback_http_ext screencapture data len %d @%d\n", len, pss->len);
+ if (len > 0) {
+ pss->len += len;
+ if (lws_write(wsi, start, len, LWS_WRITE_HTTP) != len)
+ return 1;
+ } else {
+ lwsl_info("capture done, write len %d, %d errno %d %s\n", pss->len, len, errno, strerror(errno));
+ if (len == 0 || errno != EAGAIN) {
+ lws_close_free_wsi(pss->wsi_pipe, LWS_CLOSE_STATUS_NOSTATUS, "screencap pipe");
+ pss->wsi_pipe = NULL;
+ len = lws_write(wsi, start, 0, LWS_WRITE_HTTP_FINAL);
+ complete = 1;
+ }
+ }
+ } else
+ complete = 1;
+ if (complete && lws_http_transaction_completed(wsi))
+ return -1;
+ return 0;
+ } break;
+ case LWS_CALLBACK_RAW_RX_FILE:
+ pss = lws_get_opaque_user_data(wsi);
+ lws_callback_on_writable(pss->wsi);
+ return 0;
+ case LWS_CALLBACK_RAW_CLOSE_FILE:
+ pss = lws_get_opaque_user_data(wsi);
+ pss->wsi_pipe = NULL;
+ return 0;
+ case LWS_CALLBACK_CLOSED_HTTP:
+ if (pss->wsi_pipe)
+ lws_close_free_wsi(pss->wsi_pipe, LWS_CLOSE_STATUS_NOSTATUS, "screencap pipe");
+ break;
+ default:
+ break;
+ }
+ return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
static struct lws_protocols protocols[] = {
{"http", lws_callback_http_dummy, 0, 0},
{WS_PROTOCOL_NAME, callback_ambus_ws_br, sizeof(struct json_rpc_ws_session), 0, 0, NULL, 0},
{"dbusraw", callback_dbus, 0, 0},
+ {WS_PROTOCOL_EXT, callback_http_ext, sizeof(struct http_capture_request), 0},
{NULL, NULL, 0, 0} /* terminator */
};
@@ -253,8 +365,28 @@
}
}
-static struct lws_http_mount mount = {
+static struct lws_http_mount mount_http_ext = {
/* .mount_next */ NULL, /* linked-list "next" */
+ /* .mountpoint */ "/screencapture", /* mountpoint URL */
+ /* .origin */ NULL, /* serve from dir */
+ /* .def */ NULL, /* default filename */
+ /* .protocol */ WS_PROTOCOL_EXT,
+ /* .cgienv */ NULL,
+ /* .extra_mimetypes */ NULL,
+ /* .interpret */ NULL,
+ /* .cgi_timeout */ 0,
+ /* .cache_max_age */ 0,
+ /* .auth_mask */ 0,
+ /* .cache_reusable */ 0,
+ /* .cache_revalidate */ 0,
+ /* .cache_intermediaries */ 0,
+ /* .origin_protocol */ LWSMPRO_CALLBACK, /* files in a dir */
+ /* .mountpoint_len */ 14, /* char count */
+ /* .basic_auth_login_file */ NULL,
+};
+
+static struct lws_http_mount mount = {
+ /* .mount_next */ &mount_http_ext, /* linked-list "next" */
/* .mountpoint */ "/", /* mountpoint URL */
/* .origin */ ".", /* serve from dir */
/* .def */ "index.html", /* default filename */