diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92011cc..eb563d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,8 +4,8 @@ on: push: env: - TOOLCHAIN_URL: https://github.com/openlgtv/buildroot-nc4/releases/download/webos-9f5b1a1/arm-webos-linux-gnueabi_sdk-buildroot.tar.gz - TOOLCHAIN_SHA256: de49688d9d04bd533da59beb9a21e940203b95cc6ad4958858273b53502eb99b + TOOLCHAIN_URL: https://github.com/openlgtv/buildroot-nc4/releases/download/webos-c592d84/arm-webos-linux-gnueabi_sdk-buildroot.tar.gz + TOOLCHAIN_SHA256: be5b4249177fc31b3f0120106c761f42ade54fd609a3bd090852899bbdd680b9 TOOLCHAIN_DIR: /opt/arm-webos-linux-gnueabi_sdk-buildroot TOOLCHAIN_FILE: /opt/arm-webos-linux-gnueabi_sdk-buildroot/share/buildroot/toolchainfile.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 9befcc5..5a04fe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,18 @@ cmake_minimum_required(VERSION 3.6) project(hyperion-webos VERSION 1.0 LANGUAGES C CXX) +set(_cflags_list "") +list(APPEND _cflags_list + -mcpu=cortex-a9 -mfloat-abi=softfp -mfpu=neon +) +list(JOIN _cflags_list " " COMMON_FLAGS) + add_subdirectory(libyuv) add_subdirectory(tv-native-apis) add_subdirectory(flatccrt) +add_compile_options(${_cflags_list} -Wall -Wextra -Wpedantic -Werror -DSECURITY_COMPATIBILITY) + find_package(PkgConfig REQUIRED) # --- @@ -36,7 +44,6 @@ add_custom_target(version -P ${CMAKE_SOURCE_DIR}/GenerateVersionHeader.cmake ) -add_compile_options(-Wall -Wextra -Wpedantic -Werror -DSECURITY_COMPATIBILITY) add_executable(hyperion-webos src/main.c src/settings.c diff --git a/libyuv/CMakeLists.txt b/libyuv/CMakeLists.txt index d14c04e..bbe151e 100644 --- a/libyuv/CMakeLists.txt +++ b/libyuv/CMakeLists.txt @@ -3,7 +3,14 @@ include(ExternalProject) ExternalProject_Add( libyuv URL https://chromium.googlesource.com/libyuv/libyuv/+archive/fdc71956bdade0012b0628b5011b567c06c72308.tar.gz - CMAKE_ARGS "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_SOURCE_DIR}" "-DCMAKE_POSITION_INDEPENDENT_CODE=ON" + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${COMMON_FLAGS} + -DCMAKE_CXX_FLAGS=${COMMON_FLAGS} + -DBUILD_SHARED_LIBS=OFF + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_SOURCE_DIR} + -DCMAKE_POSITION_INDEPENDENT_CODE=ON ) add_library(yuv STATIC IMPORTED GLOBAL) diff --git a/src/hyperion_client.c b/src/hyperion_client.c index 495a326..a21c7ea 100644 --- a/src/hyperion_client.c +++ b/src/hyperion_client.c @@ -10,11 +10,14 @@ #include #include #include +#include #include #include "hyperion_reply_reader.h" #include "hyperion_request_builder.h" +static int _connect_unix_socket(const char* hostname); +static int _connect_inet_socket(const char* hostname, int port); static int _send_message(const void* buffer, size_t size); static bool _parse_reply(hyperionnet_Reply_table_t reply); @@ -25,53 +28,20 @@ static const char* _origin = NULL; static bool _connected = false; unsigned char recvBuff[1024]; -int hyperion_client(const char* origin, const char* hostname, int port, int priority) +int hyperion_client(const char* origin, const char* hostname, int port, bool unix_socket, int priority) { _origin = origin; _priority = priority; _connected = false; _registered = false; sockfd = 0; - struct sockaddr_in serv_addr; - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - WARN("Could not create socket: %s", strerror(errno)); - return 1; - } - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, - sizeof(timeout)) - < 0) { - WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno)); - return 1; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, - sizeof(timeout)) - < 0) { - WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno)); - return 1; - } - - memset(&serv_addr, '0', sizeof(serv_addr)); - - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(port); - if (inet_pton(AF_INET, hostname, &serv_addr.sin_addr) <= 0) { - WARN("inet_pton error occured (hostname: %s): %s", hostname, strerror(errno)); - return 1; - } - if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { - WARN("connect() to %s:%d failed: %s", hostname, port, strerror(errno)); - return 1; + if (unix_socket) { + return _connect_unix_socket(hostname); + } else { + return _connect_inet_socket(hostname, port); } - _connected = true; - - return 0; } int hyperion_read() @@ -197,3 +167,87 @@ bool _parse_reply(hyperionnet_Reply_table_t reply) return false; } + +int _connect_inet_socket(const char* hostname, int port) +{ + struct sockaddr_in serv_addr_in; + + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WARN("Could not create socket: %s", strerror(errno)); + return 1; + } + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, + sizeof(timeout)) + < 0) { + WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno)); + return 1; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)) + < 0) { + WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno)); + return 1; + } + + memset(&serv_addr_in, 0, sizeof(serv_addr_in)); + + serv_addr_in.sin_family = AF_INET; + serv_addr_in.sin_port = htons(port); + + if (inet_pton(AF_INET, hostname, &serv_addr_in.sin_addr) <= 0) { + WARN("inet_pton error occured (hostname: %s): %s", hostname, strerror(errno)); + return 1; + } + + if (connect(sockfd, (struct sockaddr*)&serv_addr_in, sizeof(serv_addr_in)) < 0) { + WARN("connect() to %s:%d failed: %s", hostname, port, strerror(errno)); + return 1; + } + _connected = true; + + return 0; +} + +int _connect_unix_socket(const char* hostname) +{ + struct sockaddr_un serv_addr_un; + + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + WARN("Could not create socket: %s", strerror(errno)); + return 1; + } + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, + sizeof(timeout)) + < 0) { + WARN("setsockopt(SO_SNDTIMEO) failed: %s", strerror(errno)); + return 1; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)) < 0) { + WARN("setsockopt(SO_RCVTIMEO) failed: %s", strerror(errno)); + return 1; + } + + memset(&serv_addr_un, 0, sizeof(serv_addr_un)); + + serv_addr_un.sun_family = AF_LOCAL; + strcpy(serv_addr_un.sun_path, hostname); + + if (connect(sockfd, (struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) < 0) { + WARN("connect() to unix socket %s failed: %s", hostname, strerror(errno)); + return 1; + } + _connected = true; + + return 0; +} \ No newline at end of file diff --git a/src/hyperion_client.h b/src/hyperion_client.h index 5301949..315dd40 100644 --- a/src/hyperion_client.h +++ b/src/hyperion_client.h @@ -1,6 +1,7 @@ #pragma once +#include -int hyperion_client(const char* origin, const char* hostname, int port, int priority); +int hyperion_client(const char* origin, const char* hostname, int port, bool unix_socket, int priority); int hyperion_read(); int hyperion_destroy(); int hyperion_set_image(const unsigned char* image, int width, int height); diff --git a/src/main.c b/src/main.c index 7e8cfb0..8038dd7 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ static struct option long_options[] = { { "height", required_argument, 0, 'y' }, { "address", required_argument, 0, 'a' }, { "port", required_argument, 0, 'p' }, + { "unix-socket", no_argument, 0, 'l' }, { "fps", required_argument, 0, 'f' }, { "no-video", no_argument, 0, 'V' }, { "no-gui", no_argument, 0, 'G' }, @@ -52,6 +53,7 @@ static void print_usage() printf(" -y, --height=HEIGHT Height of video frame (default 108)\n"); printf(" -a, --address=ADDR IP address of Hyperion server\n"); printf(" -p, --port=PORT Port of Hyperion flatbuffers server (default 19400)\n"); + printf(" -l, --unix-socket Connect through unix socket\n"); printf(" -f, --fps=FPS Framerate for sending video frames (default 0 = unlimited)\n"); printf(" -b, --backend=BE Use specific video capture backend (default auto)\n"); printf(" -u, --ui-backend=BE Use specific ui capture backend (default auto)\n"); @@ -74,7 +76,7 @@ static int parse_options(int argc, char* argv[]) int opt, longindex; int ret; - while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:vnhdVGrs", long_options, &longindex)) != -1) { + while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:lvnhdVGrs", long_options, &longindex)) != -1) { switch (opt) { case 'x': settings.width = atoi(optarg); @@ -89,6 +91,9 @@ static int parse_options(int argc, char* argv[]) case 'p': settings.port = atol(optarg); break; + case 'l': + settings.unix_socket = true; + break; case 'f': settings.fps = atoi(optarg); break; diff --git a/src/service.c b/src/service.c index a2cdf07..135a1ac 100644 --- a/src/service.c +++ b/src/service.c @@ -28,7 +28,8 @@ void* connection_loop(void* data) DBG("Starting connection loop"); while (service->connection_loop_running) { INFO("Connecting hyperion-client.."); - if ((hyperion_client("webos", service->settings->address, service->settings->port, service->settings->priority)) != 0) { + if ((hyperion_client("webos", service->settings->address, service->settings->port, + service->settings->unix_socket, service->settings->priority)) != 0) { ERR("Error! hyperion_client."); } else { INFO("hyperion-client connected!"); @@ -415,7 +416,7 @@ static bool videooutput_callback(LSHandle* sh __attribute__((unused)), LSMessage hdr_enabled = true; } - int ret = set_hdr_state(service->settings->address, RPC_PORT, hdr_enabled); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } @@ -471,7 +472,7 @@ static bool picture_callback(LSHandle* sh __attribute__((unused)), LSMessage* ms hdr_enabled = true; } - int ret = set_hdr_state(service->settings->address, RPC_PORT, hdr_enabled); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } diff --git a/src/settings.c b/src/settings.c index d572a37..1a14904 100644 --- a/src/settings.c +++ b/src/settings.c @@ -9,6 +9,7 @@ void settings_init(settings_t* settings) settings->address = strdup(""); settings->port = 19400; settings->priority = 150; + settings->unix_socket = false; settings->fps = 30; settings->width = 320; @@ -54,6 +55,8 @@ int settings_load_json(settings_t* settings, jvalue_ref source) jnumber_get_i32(value, &settings->port); if ((value = jobject_get(source, j_cstr_to_buffer("priority"))) && jis_number(value)) jnumber_get_i32(value, &settings->priority); + if ((value = jobject_get(source, j_cstr_to_buffer("unix-socket"))) && jis_boolean(value)) + jboolean_get(value, &settings->unix_socket); if ((value = jobject_get(source, j_cstr_to_buffer("fps"))) && jis_number(value)) jnumber_get_i32(value, &settings->fps); @@ -89,6 +92,7 @@ int settings_save_json(settings_t* settings, jvalue_ref target) jobject_set(target, j_cstr_to_buffer("address"), jstring_create(settings->address)); jobject_set(target, j_cstr_to_buffer("port"), jnumber_create_i32(settings->port)); jobject_set(target, j_cstr_to_buffer("priority"), jnumber_create_i32(settings->priority)); + jobject_set(target, j_cstr_to_buffer("unix-socket"), jboolean_create(settings->unix_socket)); jobject_set(target, j_cstr_to_buffer("fps"), jnumber_create_i32(settings->fps)); jobject_set(target, j_cstr_to_buffer("width"), jnumber_create_i32(settings->width)); diff --git a/src/settings.h b/src/settings.h index bf8e907..44918ee 100644 --- a/src/settings.h +++ b/src/settings.h @@ -14,6 +14,7 @@ typedef struct _settings_t { char* address; int port; int priority; + bool unix_socket; int fps; int width;