Compare commits

...

36 Commits

Author SHA1 Message Date
Cameron Gutman
a6bf7154a7 Reduce MAX_FRAMES for RK backend
See b1d111b5f7 (r146373202)
2024-09-08 00:32:30 -05:00
Mingjie Shen
274d3db34d fix unbounded write of sprintf
Buffer write operations that do not control the length of data written
may overflow. Fix by replacing sprintf() with snprintf().
2024-03-25 00:11:49 -05:00
Cameron Gutman
014af67397 Fix build warnings 2024-02-19 22:01:31 -06:00
Cameron Gutman
eb4a202358 Version 2.7.0 2024-02-19 21:29:05 -06:00
Cameron Gutman
bac5360494 Provide better errors when RK renderer fails 2024-02-19 20:56:55 -06:00
Cameron Gutman
0e12282311 Remove a bunch of useless asserts 2024-02-19 20:49:25 -06:00
Cameron Gutman
883498d642 Replace SDL key handling with Moonlight Qt code
The existing code had a bunch of incorrectly mapped keys and was using
keysym instead of scancode which causes issues with non-US keyboards.
2024-02-19 16:16:02 -06:00
Cameron Gutman
55b49221d8 Link util.c into the platform libraries 2024-02-19 15:58:32 -06:00
Cameron Gutman
454f67b0ed Move CPU detection code into a separate file 2024-02-19 15:56:49 -06:00
Cameron Gutman
2f03600bae Ignore CRCs in SDL mappings 2024-02-19 15:45:17 -06:00
Cameron Gutman
fc904d2dac Treat devices as gamepads if they have a hat instead of an analog stick
Fixes #880
2024-02-18 14:56:57 -06:00
Cameron Gutman
d6c9650a32 Add rotation support for Rockchip
Fixes #878
2024-02-18 14:48:13 -06:00
Cameron Gutman
a9d6f17d5e Replace ioctl() retry loops with drmIoctl() 2024-02-18 14:30:59 -06:00
Cameron Gutman
ca4c517510 Update moonlight-common-c 2024-02-18 00:48:26 -06:00
Cameron Gutman
3b1b2ab51d Replace FindLibUUID.cmake with modified version from CMake project 2024-02-18 00:25:53 -06:00
Cameron Gutman
b533c52edd Add missing CMake include 2024-02-18 00:18:41 -06:00
Cameron Gutman
d89bd8d20f Update SDL_GameControllerDB 2024-02-17 23:56:23 -06:00
Cameron Gutman
8125d2194b Fix __builtin_cpu_supports(aes) on GCC 9 and earlier 2024-02-17 13:23:06 -06:00
Cameron Gutman
8fb2c72ca1 Update moonlight-common-c with RTSP encryption 2024-02-17 13:18:40 -06:00
Cameron Gutman
9255f774f2 Add fast AES detection for RISC-V using hwprobe() syscall 2024-01-23 02:46:05 -06:00
Cameron Gutman
d3d79c3224 Fix HAVE_GETAUXVAL codepath 2024-01-19 19:02:07 -06:00
Cameron Gutman
b08a04c378 Update moonlight-common-c with finalized encryption changes 2024-01-19 18:58:57 -06:00
amazingfate
5bd2799209 Support cursor plane on Rockchip platforms 2024-01-16 00:49:16 -06:00
Cameron Gutman
0712e05aab Opt in to video encryption on CPUs with good AES perf 2024-01-15 17:35:59 -06:00
Cameron Gutman
02cddf762b Update moonlight-common-c with new encryption support 2024-01-15 17:33:30 -06:00
armin-25689
810ef140cb style: make the code more prescriptive 2024-01-01 12:41:51 -06:00
armin-25689
50a7454bc1 build: use CMAKE_ARGS to control instead for FreeBSD 2024-01-01 12:41:51 -06:00
armin-25689
a610eddd97 build: change <endian.h> header file and __s32 type for FreeBSD 2024-01-01 12:41:51 -06:00
armin-25689
b3fb22d427 fix: it took so long time to connect to the Sunshine host in the FreeBSD
Disable reuse feature for FreeBSD to prevent excessive time from being spent connecting to the Sunshine host
2024-01-01 12:41:51 -06:00
armin-25689
3840b1409e feat: add oss audio callback for FreeBSD
OSS is the native sound system of the FreeBSD.It will be used on the x11_vaapi platform.It was added to reduce moonlight's dependency on FreeBSD.
2024-01-01 12:41:51 -06:00
Cameron Gutman
3b72f5195b Update moonlight-common-c with new bitrate logic 2023-12-03 22:26:22 -06:00
Cameron Gutman
000d9da4a0 Don't hardcode the signature length 2023-11-29 23:48:09 -06:00
Cameron Gutman
2aba7a10e7 Version 2.6.2 2023-11-03 01:08:34 -05:00
Cameron Gutman
0131274dce Update moonlight-common-c to fix multi-homed host bug 2023-11-03 00:56:23 -05:00
Cameron Gutman
dc03235a62 Fix several build warnings 2023-10-29 19:56:18 +00:00
Cameron Gutman
c007eabf50 Update moonlight-common-c to fix input reliability/performance issues 2023-10-25 22:55:38 -05:00
23 changed files with 776 additions and 310 deletions

View File

@ -1,10 +1,12 @@
cmake_minimum_required(VERSION 3.1)
project(moonlight-embedded VERSION 2.6.1 LANGUAGES C)
cmake_minimum_required(VERSION 3.6)
project(moonlight-embedded VERSION 2.7.0 LANGUAGES C)
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
SET(CMAKE_C_STANDARD 99)
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/generate_version_header.cmake)
include(CheckCSourceCompiles)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-pointer-sign -Wno-sign-compare -Wno-switch)
aux_source_directory(./src SRC_LIST)
@ -87,6 +89,22 @@ add_executable(moonlight ${SRC_LIST})
target_link_libraries(moonlight m)
target_link_libraries(moonlight gamestream)
if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
set(ALSA_FOUND FALSE)
target_sources(moonlight PRIVATE ./src/audio/oss.c)
endif()
check_c_source_compiles("#include <sys/auxv.h>
int main(void) { return getauxval(AT_HWCAP); }" HAVE_GETAUXVAL)
if (HAVE_GETAUXVAL)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_GETAUXVAL)
endif()
check_c_source_compiles("int main(void) { return __builtin_cpu_supports(\"aes\"); }" HAVE_BICS_AES)
if (HAVE_BICS_AES)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_BICS_AES)
endif()
if (CEC_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC)
list(APPEND MOONLIGHT_OPTIONS CEC)
@ -98,7 +116,7 @@ endif()
if(AMLOGIC_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_AML)
list(APPEND MOONLIGHT_OPTIONS AML)
add_library(moonlight-aml SHARED ./src/video/aml.c ${ILCLIENT_SRC_LIST})
add_library(moonlight-aml SHARED ./src/video/aml.c ./src/util.c ${ILCLIENT_SRC_LIST})
target_include_directories(moonlight-aml PRIVATE ${AMLOGIC_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
target_link_libraries(moonlight-aml gamestream ${AMLOGIC_LIBRARIES})
set_property(TARGET moonlight-aml PROPERTY COMPILE_DEFINITIONS ${AMLOGIC_DEFINITIONS})
@ -109,7 +127,7 @@ if(BROADCOM-OMX_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_PI)
list(APPEND MOONLIGHT_OPTIONS PI)
aux_source_directory(./third_party/ilclient ILCLIENT_SRC_LIST)
add_library(moonlight-pi SHARED ./src/video/pi.c ./src/audio/omx.c ${ILCLIENT_SRC_LIST})
add_library(moonlight-pi SHARED ./src/video/pi.c ./src/audio/omx.c ./src/util.c ${ILCLIENT_SRC_LIST})
target_include_directories(moonlight-pi PRIVATE ./third_party/ilclient ${BROADCOM_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR} ${OPUS_INCLUDE_DIRS})
target_link_libraries(moonlight-pi gamestream ${BROADCOM_OMX_LIBRARIES} ${OPUS_LIBRARY})
set_property(TARGET moonlight-pi PROPERTY COMPILE_DEFINITIONS ${BROADCOM_OMX_DEFINITIONS})
@ -119,7 +137,7 @@ endif()
if(MMAL_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_MMAL)
list(APPEND MOONLIGHT_OPTIONS MMAL)
add_library(moonlight-mmal SHARED ./src/video/mmal.c)
add_library(moonlight-mmal SHARED ./src/video/mmal.c ./src/util.c)
target_include_directories(moonlight-mmal PRIVATE ${MMAL_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
target_link_libraries(moonlight-mmal gamestream ${MMAL_LINK_LIBRARIES})
install(TARGETS moonlight-mmal DESTINATION ${CMAKE_INSTALL_LIBDIR})
@ -128,7 +146,7 @@ endif()
if(FREESCALE_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_IMX)
list(APPEND MOONLIGHT_OPTIONS IMX)
add_library(moonlight-imx SHARED ./src/video/imx.c ./src/video/imx_vpu.c)
add_library(moonlight-imx SHARED ./src/video/imx.c ./src/video/imx_vpu.c ./src/util.c)
target_include_directories(moonlight-imx PRIVATE ${FREESCALE_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
target_link_libraries(moonlight-imx gamestream ${FREESCALE_LIBRARIES})
install(TARGETS moonlight-imx DESTINATION ${CMAKE_INSTALL_LIBDIR})
@ -137,7 +155,7 @@ endif()
if(ROCKCHIP_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_ROCKCHIP)
list(APPEND MOONLIGHT_OPTIONS ROCKCHIP)
add_library(moonlight-rk SHARED ./src/video/rk.c)
add_library(moonlight-rk SHARED ./src/video/rk.c ./src/util.c)
target_include_directories(moonlight-rk PRIVATE ${ROCKCHIP_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
target_link_libraries(moonlight-rk gamestream ${ROCKCHIP_LIBRARIES})
set_property(TARGET moonlight-rk PROPERTY COMPILE_DEFINITIONS ${ROCKCHIP_DEFINITIONS})

View File

@ -1,51 +1,77 @@
# - Try to find LIBUUID
# Find LIBUUID headers, libraries and the answer to all questions.
# CMake - Cross Platform Makefile Generator
# Copyright 2000-2024 Kitware, Inc. and Contributors
# All rights reserved.
#
# LIBUUID_FOUND True if libuuid got found
# LIBUUID_INCLUDE_DIRS Location of libuuid headers
# LIBUUID_LIBRARIES List of libraries to use libuuid
#
# Copyright (c) 2008 Bjoern Ricks <bjoern.ricks@googlemail.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Distributed under the OSI-approved BSD 3-Clause License. See
# https://cmake.org/licensing for details.
#
#[=======================================================================[.rst:
FindLibUUID
------------
INCLUDE( FindPkgConfig )
Find LibUUID include directory and library.
IF ( LibUuid_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "REQUIRED" )
ELSE( LibUuid_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "" )
ENDIF ( LibUuid_FIND_REQUIRED )
Imported Targets
^^^^^^^^^^^^^^^^
IF ( LIBUUID_MIN_VERSION )
PKG_SEARCH_MODULE( LIBUUID ${_pkgconfig_REQUIRED} uuid>=${LIBUUID_MIN_VERSION} )
ELSE ( LIBUUID_MIN_VERSION )
PKG_SEARCH_MODULE( LIBUUID ${_pkgconfig_REQUIRED} uuid )
ENDIF ( LIBUUID_MIN_VERSION )
An :ref:`imported target <Imported targets>` named
``LibUUID::LibUUID`` is provided if LibUUID has been found.
Result Variables
^^^^^^^^^^^^^^^^
IF( NOT LIBUUID_FOUND AND NOT PKG_CONFIG_FOUND )
FIND_PATH( LIBUUID_INCLUDE_DIRS uuid/uuid.h )
FIND_LIBRARY( LIBUUID_LIBRARIES uuid)
This module defines the following variables:
# Report results
IF ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS )
SET( LIBUUID_FOUND 1 )
IF ( NOT LIBUUID_FIND_QUIETLY )
MESSAGE( STATUS "Found libuuid: ${LIBUUID_LIBRARIES}" )
ENDIF ( NOT LIBUUID_FIND_QUIETLY )
ELSE ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS )
IF ( LIBUUID_FIND_REQUIRED )
MESSAGE( SEND_ERROR "Could NOT find libuuid" )
ELSE ( LIBUUID_FIND_REQUIRED )
IF ( NOT LIBUUID_FIND_QUIETLY )
MESSAGE( STATUS "Could NOT find libuuid" )
ENDIF ( NOT LIBUUID_FIND_QUIETLY )
ENDIF ( LIBUUID_FIND_REQUIRED )
ENDIF ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS )
ENDIF( NOT LIBUUID_FOUND AND NOT PKG_CONFIG_FOUND )
``LibUUID_FOUND``
True if LibUUID was found, false otherwise.
``LibUUID_INCLUDE_DIRS``
Include directories needed to include LibUUID headers.
``LibUUID_LIBRARIES``
Libraries needed to link to LibUUID.
MARK_AS_ADVANCED( LIBUUID_LIBRARIES LIBUUID_INCLUDE_DIRS )
Cache Variables
^^^^^^^^^^^^^^^
This module uses the following cache variables:
``LibUUID_LIBRARY``
The location of the LibUUID library file.
``LibUUID_INCLUDE_DIR``
The location of the LibUUID include directory containing ``uuid/uuid.h``.
The cache variables should not be used by project code.
They may be set by end users to point at LibUUID components.
#]=======================================================================]
#-----------------------------------------------------------------------------
find_library(LibUUID_LIBRARY
NAMES uuid
)
mark_as_advanced(LibUUID_LIBRARY)
find_path(LibUUID_INCLUDE_DIR
NAMES uuid/uuid.h
)
mark_as_advanced(LibUUID_INCLUDE_DIR)
#-----------------------------------------------------------------------------
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUUID
FOUND_VAR LibUUID_FOUND
REQUIRED_VARS LibUUID_LIBRARY LibUUID_INCLUDE_DIR
)
set(LIBUUID_FOUND ${LibUUID_FOUND})
#-----------------------------------------------------------------------------
# Provide documented result variables and targets.
if(LibUUID_FOUND)
set(LibUUID_INCLUDE_DIRS ${LibUUID_INCLUDE_DIR})
set(LibUUID_LIBRARIES ${LibUUID_LIBRARY})
if(NOT TARGET LibUUID::LibUUID)
add_library(LibUUID::LibUUID UNKNOWN IMPORTED)
set_target_properties(LibUUID::LibUUID PROPERTIES
IMPORTED_LOCATION "${LibUUID_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LibUUID_INCLUDE_DIRS}"
)
endif()
endif()

View File

@ -23,9 +23,9 @@ target_link_libraries(gamestream moonlight-common)
set_target_properties(gamestream PROPERTIES SOVERSION ${SO_VERSION} VERSION ${PROJECT_VERSION})
set_target_properties(moonlight-common PROPERTIES SOVERSION ${SO_VERSION} VERSION ${PROJECT_VERSION})
target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c/src ../third_party/h264bitstream ${AVAHI_INCLUDE_DIRS} ${LIBUUID_INCLUDE_DIRS})
target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c/src ../third_party/h264bitstream ${AVAHI_INCLUDE_DIRS} ${LibUUID_INCLUDE_DIRS})
target_include_directories(moonlight-common PRIVATE ../third_party/moonlight-common-c/reedsolomon ../third_party/moonlight-common-c/enet/include)
target_link_libraries(gamestream ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${LIBUUID_LIBRARIES})
target_link_libraries(gamestream ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${LibUUID_LIBRARIES})
target_link_libraries(gamestream ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})

View File

@ -48,7 +48,7 @@
static char unique_id[UNIQUEID_CHARS+1];
static X509 *cert;
static char cert_hex[4096];
static char cert_hex[8192];
static EVP_PKEY *privateKey;
const char* gs_error;
@ -56,8 +56,6 @@ const char* gs_error;
#define LEN_AS_HEX_STR(x) ((x) * 2 + 1)
#define SIZEOF_AS_HEX_STR(x) LEN_AS_HEX_STR(sizeof(x))
#define SIGNATURE_LEN 256
#define UUID_STRLEN 37
static int mkdirtree(const char* directory) {
@ -310,6 +308,12 @@ static void bytes_to_hex(unsigned char *in, char *out, size_t len) {
out[len * 2] = 0;
}
static void hex_to_bytes(const char *in, unsigned char* out, size_t len) {
for (int count = 0; count < len; count += 2) {
sscanf(&in[count], "%2hhx", &out[count / 2]);
}
}
static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *slen, EVP_PKEY *pkey) {
int result = GS_FAILED;
@ -422,13 +426,21 @@ int gs_unpair(PSERVER_DATA server) {
int gs_pair(PSERVER_DATA server, char* pin) {
int ret = GS_OK;
char* result = NULL;
char url[5120];
size_t url_max_len = 16384;
char* url = malloc(url_max_len);
uuid_t uuid;
char uuid_str[UUID_STRLEN];
char* plaincert = NULL;
char* challenge_response = NULL;
char* pairing_secret = NULL;
char* client_pairing_secret = NULL;
char* client_pairing_secret_hex = NULL;
PHTTP_DATA data = NULL;
if (server->paired) {
gs_error = "Already paired";
return GS_WRONG_STATE;
ret = GS_WRONG_STATE;
goto cleanup;
}
unsigned char salt_data[16];
@ -438,8 +450,8 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, salt_hex, cert_hex);
PHTTP_DATA data = http_create_data();
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, salt_hex, cert_hex);
data = http_create_data();
if (data == NULL)
return GS_OUT_OF_MEMORY;
else if ((ret = http_request(url, data)) != GS_OK)
@ -461,18 +473,11 @@ int gs_pair(PSERVER_DATA server, char* pin) {
if ((ret = xml_search(data->memory, data->size, "plaincert", &result)) != GS_OK)
goto cleanup;
char plaincert[8192];
if (strlen(result)/2 > sizeof(plaincert) - 1) {
gs_error = "Server certificate too big";
ret = GS_FAILED;
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &plaincert[count / 2]);
}
plaincert[strlen(result)/2] = '\0';
size_t plaincertlen = strlen(result)/2;
plaincert = malloc(plaincertlen + 1);
hex_to_bytes(result, plaincert, plaincertlen*2);
plaincert[plaincertlen] = 0;
unsigned char salt_pin[sizeof(salt_data) + 4];
unsigned char aes_key[32]; // Must fit SHA256
@ -494,7 +499,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -527,10 +532,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &challenge_response_data_enc[count / 2]);
}
hex_to_bytes(result, challenge_response_data_enc, strlen(result));
decrypt(challenge_response_data_enc, sizeof(challenge_response_data_enc), aes_key, challenge_response_data);
char client_secret_data[16];
@ -539,7 +541,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
const ASN1_BIT_STRING *asnSignature;
X509_get0_signature(&asnSignature, NULL, cert);
char challenge_response[16 + SIGNATURE_LEN + sizeof(client_secret_data)];
challenge_response = malloc(16 + asnSignature->length + sizeof(client_secret_data));
char challenge_response_hash[32];
char challenge_response_hash_enc[sizeof(challenge_response_hash)];
char challenge_response_hex[SIZEOF_AS_HEX_STR(challenge_response_hash_enc)];
@ -556,7 +558,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_response_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_response_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -580,19 +582,15 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
char pairing_secret[16 + SIGNATURE_LEN];
if (strlen(result) / 2 > sizeof(pairing_secret)) {
gs_error = "Pairing secret too big";
ret = GS_FAILED;
size_t pairing_secret_len = strlen(result) / 2;
if (pairing_secret_len <= 16) {
ret = GS_INVALID;
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &pairing_secret[count / 2]);
}
if (!verifySignature(pairing_secret, 16, pairing_secret+16, SIGNATURE_LEN, plaincert)) {
pairing_secret = malloc(pairing_secret_len);
hex_to_bytes(result, pairing_secret, pairing_secret_len*2);
if (!verifySignature(pairing_secret, 16, pairing_secret+16, pairing_secret_len-16, plaincert)) {
gs_error = "MITM attack detected";
ret = GS_FAILED;
goto cleanup;
@ -606,15 +604,15 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
char client_pairing_secret[sizeof(client_secret_data) + SIGNATURE_LEN];
char client_pairing_secret_hex[SIZEOF_AS_HEX_STR(client_pairing_secret)];
client_pairing_secret = malloc(sizeof(client_secret_data) + s_len);
client_pairing_secret_hex = malloc(LEN_AS_HEX_STR(sizeof(client_secret_data) + s_len));
memcpy(client_pairing_secret, client_secret_data, sizeof(client_secret_data));
memcpy(client_pairing_secret + sizeof(client_secret_data), signature, SIGNATURE_LEN);
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, sizeof(client_secret_data) + SIGNATURE_LEN);
memcpy(client_pairing_secret + sizeof(client_secret_data), signature, s_len);
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, sizeof(client_secret_data) + s_len);
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, client_pairing_secret_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, client_pairing_secret_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -633,7 +631,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "https://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, server->httpsPort, unique_id, uuid_str);
snprintf(url, url_max_len, "https://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, server->httpsPort, unique_id, uuid_str);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -656,8 +654,13 @@ int gs_pair(PSERVER_DATA server, char* pin) {
if (ret != GS_OK)
gs_unpair(server);
if (result != NULL)
free(result);
free(url);
free(plaincert);
free(challenge_response);
free(pairing_secret);
free(client_pairing_secret);
free(client_pairing_secret_hex);
free(result);
http_free_data(data);
@ -738,9 +741,10 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
int surround_info = SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(config->audioConfiguration);
snprintf(url, sizeof(url), "https://%s:%u/%s?uniqueid=%s&uuid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d%s",
snprintf(url, sizeof(url), "https://%s:%u/%s?uniqueid=%s&uuid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d%s%s",
server->serverInfo.address, server->httpsPort, server->currentGame ? "resume" : "launch", unique_id, uuid_str, appId, config->width, config->height, fps, sops, rikey_hex, rikeyid, localaudio, surround_info, gamepad_mask, gamepad_mask,
(config->supportedVideoFormats & VIDEO_FORMAT_MASK_10BIT) ? "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0" : "");
(config->supportedVideoFormats & VIDEO_FORMAT_MASK_10BIT) ? "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0" : "",
LiGetLaunchUrlQueryParameters());
if ((ret = http_request(url, data)) == GS_OK)
server->currentGame = appId;
else

View File

@ -51,10 +51,10 @@ int http_init(const char* keyDirectory, int logLevel) {
return GS_FAILED;
char certificateFilePath[4096];
sprintf(certificateFilePath, "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME);
snprintf(certificateFilePath, sizeof(certificateFilePath), "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME);
char keyFilePath[4096];
sprintf(&keyFilePath[0], "%s/%s", keyDirectory, KEY_FILE_NAME);
snprintf(keyFilePath, sizeof(keyFilePath), "%s/%s", keyDirectory, KEY_FILE_NAME);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
@ -73,6 +73,9 @@ int http_init(const char* keyDirectory, int logLevel) {
int http_request(char* url, PHTTP_DATA data) {
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
curl_easy_setopt(curl, CURLOPT_URL, url);
#ifdef __FreeBSD__
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
#endif
if (debug)
printf("Request %s\n", url);

View File

@ -31,3 +31,6 @@ extern AUDIO_RENDERER_CALLBACKS audio_callbacks_sdl;
extern AUDIO_RENDERER_CALLBACKS audio_callbacks_pulse;
bool audio_pulse_init(char* audio_device);
#endif
#ifdef __FreeBSD__
extern AUDIO_RENDERER_CALLBACKS audio_callbacks_oss;
#endif

105
src/audio/oss.c Normal file
View File

@ -0,0 +1,105 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2015-2017 Iwan Timmer
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __FreeBSD__
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include "audio.h"
#include <opus_multistream.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static OpusMSDecoder* decoder;
static short* pcmBuffer;
static int samplesPerFrame;
static int channelCount;
static int fd = -1;
static int oss_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int arFlags) {
int rc;
decoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams, opusConfig->coupledStreams, opusConfig->mapping, &rc);
channelCount = opusConfig->channelCount;
samplesPerFrame = opusConfig->samplesPerFrame;
pcmBuffer = malloc(sizeof(short) * channelCount * samplesPerFrame);
if (pcmBuffer == NULL)
return -1;
const char* oss_name = "/dev/dsp";
fd = open(oss_name, O_WRONLY);
if (fd == -1) {
printf("Open audio device /dev/dsp failed! error %d\n", errno);
return -1;
}
// buffer size for fragment ,selector 12 is 4096;11 is 2048;10 is 1024; 13is 8192
int frag = 12;
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag) == -1)
printf("Set fragment for /dev/dsp failed.");
int format = AFMT_S16_LE;
int channels = opusConfig->channelCount;
int rate = opusConfig->sampleRate;
if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1)
printf("Set format for /dev/dsp failed.");
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1)
printf("Set channels for /dev/dsp failed.");
if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) == -1)
printf("Set sample rate for /dev/dsp failed.");
return 0;
}
static void oss_renderer_cleanup() {
if (decoder != NULL) {
opus_multistream_decoder_destroy(decoder);
decoder = NULL;
}
if (pcmBuffer != NULL) {
free(pcmBuffer);
pcmBuffer = NULL;
}
if (fd != -1) {
close(fd);
fd = -1;
}
}
static void oss_renderer_decode_and_play_sample(char* data, int length) {
int decodeLen = opus_multistream_decode(decoder, data, length, pcmBuffer, samplesPerFrame, 0);
if (decodeLen > 0) {
write(fd, pcmBuffer, decodeLen * channelCount * sizeof(short));
} else if (decodeLen < 0) {
printf("Opus error from decode: %d\n", decodeLen);
}
}
AUDIO_RENDERER_CALLBACKS audio_callbacks_oss = {
.init = oss_renderer_init,
.cleanup = oss_renderer_cleanup,
.decodeAndPlaySample = oss_renderer_decode_and_play_sample,
.capabilities = CAPABILITY_DIRECT_SUBMIT | CAPABILITY_SUPPORTS_ARBITRARY_AUDIO_DURATION,
};
#endif

View File

@ -20,6 +20,7 @@
#include "platform.h"
#include "config.h"
#include "util.h"
#include "cpu.h"
#include "input/evdev.h"
#include "audio/audio.h"
@ -348,20 +349,19 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) {
config->stream.streamingRemotely = STREAM_CFG_AUTO;
config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
config->stream.supportedVideoFormats = SCM_H264;
config->stream.encryptionFlags = ENCFLG_AUDIO;
#ifdef __arm__
char cpuinfo[4096] = {};
if (read_file("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo) - 1) > 0) {
// If this is a ARMv6 CPU (like the Pi 1), we'll assume it's not
// powerful enough to handle audio encryption. The Pi 1 could
// barely handle Opus decoding alone.
if (strstr(cpuinfo, "ARMv6")) {
config->stream.encryptionFlags = ENCFLG_NONE;
printf("Disabling audio encryption on low performance CPU\n");
}
// Opt in for video encryption if the CPU has good AES performance
if (has_fast_aes()) {
config->stream.encryptionFlags = ENCFLG_ALL;
}
else if (has_slow_aes()) {
// For extremely slow CPUs, opt out of audio encryption
config->stream.encryptionFlags = ENCFLG_NONE;
printf("Disabling encryption on low performance CPU\n");
}
else {
config->stream.encryptionFlags = ENCFLG_AUDIO;
}
#endif
config->debug_level = 0;
config->platform = "auto";
@ -411,11 +411,11 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) {
struct passwd *pw = getpwuid(getuid());
const char *dir;
if ((dir = getenv("XDG_CACHE_DIR")) != NULL)
sprintf(config->key_dir, "%s" MOONLIGHT_PATH, dir);
snprintf(config->key_dir, sizeof(config->key_dir), "%s" MOONLIGHT_PATH, dir);
else if ((dir = getenv("HOME")) != NULL)
sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir);
snprintf(config->key_dir, sizeof(config->key_dir), "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir);
else
sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir);
snprintf(config->key_dir, sizeof(config->key_dir), "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir);
}
if (config->stream.bitrate == -1) {

121
src/cpu.c Normal file
View File

@ -0,0 +1,121 @@
/*
* This file is part of Moonlight Embedded.
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
#include "util.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_GETAUXVAL
#include <sys/auxv.h>
#ifndef HWCAP2_AES
#define HWCAP2_AES (1 << 0)
#endif
#endif
#if defined(__linux__) && defined(__riscv)
#if __has_include(<sys/hwprobe.h>)
#include <sys/hwprobe.h>
#else
#include <unistd.h>
#if __has_include(<asm/hwprobe.h>)
#include <asm/hwprobe.h>
#include <sys/syscall.h>
#else
#define __NR_riscv_hwprobe 258
struct riscv_hwprobe {
int64_t key;
uint64_t value;
};
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#endif
// RISC-V Scalar AES [E]ncryption and [D]ecryption
#ifndef RISCV_HWPROBE_EXT_ZKND
#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
#define RISCV_HWPROBE_EXT_ZKNE (1 << 12)
#endif
// RISC-V Vector AES
#ifndef RISCV_HWPROBE_EXT_ZVKNED
#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21)
#endif
static int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
size_t cpu_count, unsigned long *cpus,
unsigned int flags)
{
return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags);
}
#endif
#endif
bool has_fast_aes() {
#if defined(HAVE_GETAUXVAL) && (defined(__arm__) || defined(__aarch64__))
#if defined(__arm__) && defined(HWCAP2_AES)
return !!(getauxval(AT_HWCAP2) & HWCAP2_AES);
#elif defined(__aarch64__)
return !!(getauxval(AT_HWCAP) & HWCAP_AES);
#else
return false;
#endif
#elif defined(HAVE_BICS_AES)
return __builtin_cpu_supports("aes");
#elif defined(__BUILTIN_CPU_SUPPORTS__) && defined(__powerpc__)
return __builtin_cpu_supports("vcrypto");
#elif defined(__linux__) && defined(__riscv)
struct riscv_hwprobe pairs[1] = {
{ RISCV_HWPROBE_KEY_IMA_EXT_0, 0 },
};
// If this syscall is not implemented, we'll get -ENOSYS
// and the value field will remain zero.
__riscv_hwprobe(pairs, sizeof(pairs) / sizeof(struct riscv_hwprobe), 0, NULL, 0);
return (pairs[0].value & (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND)) ==
(RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND) ||
(pairs[0].value & RISCV_HWPROBE_EXT_ZVKNED);
#elif __SIZEOF_SIZE_T__ == 4
#warning Unknown 32-bit platform. Assuming AES is slow on this CPU.
return false;
#else
#warning Unknown 64-bit platform. Assuming AES is fast on this CPU.
return true;
#endif
}
bool has_slow_aes() {
#ifdef __arm__
char cpuinfo[4096] = {};
if (read_file("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo) - 1) > 0) {
// If this is a ARMv6 CPU (like the Pi 1), we'll assume it's not
// powerful enough to handle audio encryption. The Pi 1 could
// barely handle Opus decoding alone.
if (strstr(cpuinfo, "ARMv6")) {
return true;
}
}
#endif
return false;
}

21
src/cpu.h Normal file
View File

@ -0,0 +1,21 @@
/*
* This file is part of Moonlight Embedded.
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
bool has_fast_aes(void);
bool has_slow_aes(void);

View File

@ -90,7 +90,7 @@ void cec_init() {
g_iface.init_video_standalone(g_iface.connection);
cec_adapter devices[10];
int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL);
int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices[0]), NULL);
if (iDevicesFound <= 0) {
fprintf(stderr, "No CEC devices found\n");

View File

@ -38,7 +38,11 @@
#include <limits.h>
#include <unistd.h>
#include <pthread.h>
#ifdef __linux__
#include <endian.h>
#else
#include <sys/endian.h>
#endif
#include <math.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
@ -66,8 +70,13 @@ struct input_device {
int hats_state[3][2];
int fd;
char modifiers;
#ifdef __linux__
__s32 mouseDeltaX, mouseDeltaY, mouseVScroll, mouseHScroll;
__s32 touchDownX, touchDownY, touchX, touchY;
#else
int32_t mouseDeltaX, mouseDeltaY, mouseVScroll, mouseHScroll;
int32_t touchDownX, touchDownY, touchX, touchY;
#endif
struct timeval touchDownTime;
struct timeval btnDownTime;
short controllerId;
@ -827,8 +836,10 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose, in
libevdev_has_event_code(evdev, EV_ABS, ABS_RZ))) &&
!libevdev_has_event_type(evdev, EV_KEY);
bool is_gamepad =
libevdev_has_event_code(evdev, EV_ABS, ABS_X) &&
libevdev_has_event_code(evdev, EV_ABS, ABS_Y) &&
((libevdev_has_event_code(evdev, EV_ABS, ABS_X) &&
libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) ||
(libevdev_has_event_code(evdev, EV_ABS, ABS_HAT0X) &&
libevdev_has_event_code(evdev, EV_ABS, ABS_HAT0Y))) &&
(libevdev_has_event_code(evdev, EV_KEY, BTN_TRIGGER) ||
libevdev_has_event_code(evdev, EV_KEY, BTN_A) ||
libevdev_has_event_code(evdev, EV_KEY, BTN_1) ||
@ -1009,9 +1020,9 @@ void evdev_map(char* device) {
for (int i = 0; i < 16; i++)
buf += sprintf(buf, "%02x", ((unsigned char*) guid)[i]);
struct mapping map;
strncpy(map.name, name, sizeof(map.name));
strncpy(map.guid, str_guid, sizeof(map.guid));
struct mapping map = {0};
strncpy(map.name, name, sizeof(map.name) - 1);
strncpy(map.guid, str_guid, sizeof(map.guid) - 1);
libevdev_free(evdev);
close(fd);

View File

@ -38,8 +38,8 @@ struct mapping* mapping_parse(char* mapping) {
exit(EXIT_FAILURE);
}
strncpy(map->guid, guid, sizeof(map->guid));
strncpy(map->name, name, sizeof(map->name));
strncpy(map->guid, guid, sizeof(map->guid) - 1);
strncpy(map->name, name, sizeof(map->name) - 1);
/* Initialize all mapping indices to -1 to ensure they won't match anything */
memset(&map->abs_leftx, -1, offsetof(struct mapping, next) - offsetof(struct mapping, abs_leftx));
@ -58,7 +58,7 @@ struct mapping* mapping_parse(char* mapping) {
value++;
}
if (strcmp("platform", key) == 0)
strncpy(map->platform, value, sizeof(map->platform));
strncpy(map->platform, value, sizeof(map->platform) - 1);
else if (sscanf(value, "b%d", &int_value) == 1) {
if (strcmp("a", key) == 0)
map->btn_a = int_value;
@ -152,6 +152,8 @@ struct mapping* mapping_parse(char* mapping) {
map->hat_dpdown = int_value;
map->hat_dir_dpdown = direction_value;
}
} else if (strcmp("crc", key) == 0) {
/* CRC is not supported */
} else
fprintf(stderr, "Can't map (%s)\n", option);
} else if (ret == 0 && option[0] != '\n')

View File

@ -59,11 +59,232 @@ typedef struct _GAMEPAD_STATE {
static GAMEPAD_STATE gamepads[MAX_GAMEPADS];
static int keyboard_modifiers;
static int activeGamepadMask = 0;
int sdl_gamepads = 0;
#define VK_0 0x30
#define VK_A 0x41
// These are real Windows VK_* codes
#ifndef VK_F1
#define VK_F1 0x70
#define VK_F13 0x7C
#define VK_NUMPAD0 0x60
#endif
int vk_for_sdl_scancode(SDL_Scancode scancode) {
// Set keycode. We explicitly use scancode here because GFE will try to correct
// for AZERTY layouts on the host but it depends on receiving VK_ values matching
// a QWERTY layout to work.
if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_9) {
// SDL defines SDL_SCANCODE_0 > SDL_SCANCODE_9, so we need to handle that manually
return (scancode - SDL_SCANCODE_1) + VK_0 + 1;
}
else if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_Z) {
return (scancode - SDL_SCANCODE_A) + VK_A;
}
else if (scancode >= SDL_SCANCODE_F1 && scancode <= SDL_SCANCODE_F12) {
return (scancode - SDL_SCANCODE_F1) + VK_F1;
}
else if (scancode >= SDL_SCANCODE_F13 && scancode <= SDL_SCANCODE_F24) {
return (scancode - SDL_SCANCODE_F13) + VK_F13;
}
else if (scancode >= SDL_SCANCODE_KP_1 && scancode <= SDL_SCANCODE_KP_9) {
// SDL defines SDL_SCANCODE_KP_0 > SDL_SCANCODE_KP_9, so we need to handle that manually
return (scancode - SDL_SCANCODE_KP_1) + VK_NUMPAD0 + 1;
}
else {
switch (scancode) {
case SDL_SCANCODE_BACKSPACE:
return 0x08;
case SDL_SCANCODE_TAB:
return 0x09;
case SDL_SCANCODE_CLEAR:
return 0x0C;
case SDL_SCANCODE_KP_ENTER:
case SDL_SCANCODE_RETURN:
return 0x0D;
case SDL_SCANCODE_PAUSE:
return 0x13;
case SDL_SCANCODE_CAPSLOCK:
return 0x14;
case SDL_SCANCODE_ESCAPE:
return 0x1B;
case SDL_SCANCODE_SPACE:
return 0x20;
case SDL_SCANCODE_PAGEUP:
return 0x21;
case SDL_SCANCODE_PAGEDOWN:
return 0x22;
case SDL_SCANCODE_END:
return 0x23;
case SDL_SCANCODE_HOME:
return 0x24;
case SDL_SCANCODE_LEFT:
return 0x25;
case SDL_SCANCODE_UP:
return 0x26;
case SDL_SCANCODE_RIGHT:
return 0x27;
case SDL_SCANCODE_DOWN:
return 0x28;
case SDL_SCANCODE_SELECT:
return 0x29;
case SDL_SCANCODE_EXECUTE:
return 0x2B;
case SDL_SCANCODE_PRINTSCREEN:
return 0x2C;
case SDL_SCANCODE_INSERT:
return 0x2D;
case SDL_SCANCODE_DELETE:
return 0x2E;
case SDL_SCANCODE_HELP:
return 0x2F;
case SDL_SCANCODE_KP_0:
// See comment above about why we only handle SDL_SCANCODE_KP_0 here
return VK_NUMPAD0;
case SDL_SCANCODE_0:
// See comment above about why we only handle SDL_SCANCODE_0 here
return VK_0;
case SDL_SCANCODE_KP_MULTIPLY:
return 0x6A;
case SDL_SCANCODE_KP_PLUS:
return 0x6B;
case SDL_SCANCODE_KP_COMMA:
return 0x6C;
case SDL_SCANCODE_KP_MINUS:
return 0x6D;
case SDL_SCANCODE_KP_PERIOD:
return 0x6E;
case SDL_SCANCODE_KP_DIVIDE:
return 0x6F;
case SDL_SCANCODE_NUMLOCKCLEAR:
return 0x90;
case SDL_SCANCODE_SCROLLLOCK:
return 0x91;
case SDL_SCANCODE_LSHIFT:
return 0xA0;
case SDL_SCANCODE_RSHIFT:
return 0xA1;
case SDL_SCANCODE_LCTRL:
return 0xA2;
case SDL_SCANCODE_RCTRL:
return 0xA3;
case SDL_SCANCODE_LALT:
return 0xA4;
case SDL_SCANCODE_RALT:
return 0xA5;
case SDL_SCANCODE_LGUI:
return 0x5B;
case SDL_SCANCODE_RGUI:
return 0x5C;
case SDL_SCANCODE_APPLICATION:
return 0x5D;
case SDL_SCANCODE_AC_BACK:
return 0xA6;
case SDL_SCANCODE_AC_FORWARD:
return 0xA7;
case SDL_SCANCODE_AC_REFRESH:
return 0xA8;
case SDL_SCANCODE_AC_STOP:
return 0xA9;
case SDL_SCANCODE_AC_SEARCH:
return 0xAA;
case SDL_SCANCODE_AC_BOOKMARKS:
return 0xAB;
case SDL_SCANCODE_AC_HOME:
return 0xAC;
case SDL_SCANCODE_SEMICOLON:
return 0xBA;
case SDL_SCANCODE_EQUALS:
return 0xBB;
case SDL_SCANCODE_COMMA:
return 0xBC;
case SDL_SCANCODE_MINUS:
return 0xBD;
case SDL_SCANCODE_PERIOD:
return 0xBE;
case SDL_SCANCODE_SLASH:
return 0xBF;
case SDL_SCANCODE_GRAVE:
return 0xC0;
case SDL_SCANCODE_LEFTBRACKET:
return 0xDB;
case SDL_SCANCODE_BACKSLASH:
return 0xDC;
case SDL_SCANCODE_RIGHTBRACKET:
return 0xDD;
case SDL_SCANCODE_APOSTROPHE:
return 0xDE;
case SDL_SCANCODE_NONUSBACKSLASH:
return 0xE2;
default:
return 0;
}
}
}
static void send_controller_arrival(PGAMEPAD_STATE state) {
#if SDL_VERSION_ATLEAST(2, 0, 18)
unsigned int supportedButtonFlags = 0;
@ -274,57 +495,30 @@ int sdlinput_handle_event(SDL_Window* window, SDL_Event* event) {
return 0;
case SDL_KEYDOWN:
case SDL_KEYUP:
button = event->key.keysym.sym;
if (button >= 0x21 && button <= 0x2f)
button = keyCodes1[button - 0x21];
else if (button >= 0x3a && button <= 0x40)
button = keyCodes2[button - 0x3a];
else if (button >= 0x5b && button <= 0x60)
button = keyCodes3[button - 0x5b];
else if (button >= 0x40000039 && button < 0x40000039 + sizeof(keyCodes4))
button = keyCodes4[button - 0x40000039];
else if (button >= 0x400000E0 && button <= 0x400000E7)
button = keyCodes5[button - 0x400000E0];
else if (button >= 0x61 && button <= 0x7a)
button -= 0x20;
else if (button == 0x7f)
button = 0x2e;
button = vk_for_sdl_scancode(event->key.keysym.scancode);
int modifier = 0;
switch (event->key.keysym.sym) {
case SDLK_RSHIFT:
case SDLK_LSHIFT:
modifier = MODIFIER_SHIFT;
break;
case SDLK_RALT:
case SDLK_LALT:
modifier = MODIFIER_ALT;
break;
case SDLK_RCTRL:
case SDLK_LCTRL:
modifier = MODIFIER_CTRL;
break;
case SDLK_RGUI:
case SDLK_LGUI:
modifier = MODIFIER_META;
break;
int modifiers = 0;
if (event->key.keysym.mod & KMOD_CTRL) {
modifiers |= MODIFIER_CTRL;
}
if (event->key.keysym.mod & KMOD_ALT) {
modifiers |= MODIFIER_ALT;
}
if (event->key.keysym.mod & KMOD_SHIFT) {
modifiers |= MODIFIER_SHIFT;
}
if (event->key.keysym.mod & KMOD_GUI) {
modifiers |= MODIFIER_META;
}
if (modifier != 0) {
if (event->type==SDL_KEYDOWN)
keyboard_modifiers |= modifier;
else
keyboard_modifiers &= ~modifier;
}
LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers);
LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, modifiers);
// Quit the stream if all the required quit keys are down
if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP)
if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP)
return SDL_QUIT_APPLICATION;
else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP)
else if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP)
return SDL_TOGGLE_FULLSCREEN;
else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_KEY && event->type==SDL_KEYUP)
else if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_KEY && event->type==SDL_KEYUP)
return SDL_GetRelativeMouseMode() ? SDL_MOUSE_UNGRAB : SDL_MOUSE_GRAB;
break;
case SDL_FINGERDOWN:

View File

@ -22,83 +22,6 @@
extern int sdl_gamepads;
static const short keyCodes1[] = {
0, //SDLK_EXCLAIM
0, //SDLK_QUOTEDBL
0, //SDLK_HASH
0, //SDLK_DOLLAR
0, //SDLK_PERCENT
0, //SDLK_AMPERSAND
0xDE, //SDLK_QUOTE
0, //SDLK_LEFTPAREN
0, //SDLK_RIGHTPAREN
0, //SDLK_ASTERISK
0, //SDLK_PLUS
0xBC, //SDLK_COMMA
0xBD, //SDLK_MINUS
0xBE, //SDLK_PERIOD
0xBF, //SDLK_SLASH
};
static const short keyCodes2[] = {
0, //SDLK_COLON
0xBA, //SDLK_SEMICOLON
0, //SDLK_LESS
0xBB, //SDLK_EQUALS
0, //SDLK_GREATER
0, //SDLK_QUESTION
0, //SDLK_AT
};
static const short keyCodes3[] = {
0xDB, //SDLK_LEFTBRACKET
0xDC, //SDLK_BACKSLASH
0xDD, //SDLK_RIGHTBRACKET
0, //SDLK_CARET
0, //SDLK_UNDERSCORE
0xC0, //SDLK_BACKQUOTE
};
static const short keyCodes4[] = {
0x14, //SDLK_CAPSLOCK
0x70, //SDLK_F1
0x71, //SDLK_F2
0x72, //SDLK_F3
0x73, //SDLK_F4
0x74, //SDLK_F5
0x75, //SDLK_F6
0x76, //SDLK_F7
0x77, //SDLK_F8
0x78, //SDLK_F9
0x79, //SDLK_F10
0x7A, //SDLK_F11
0x7B, //SDLK_F12
0, //SDLK_PRINTSCREEN
0x91, //SDLK_SCROLLLOCK
0x13, //SDLK_PAUSE
0x2D, //SDLK_INSERT
0x24, //SDLK_HOME
0x21, //SDLK_PAGEUP
0, //Not used
0x23, //SDLK_END
0x22, //SDLK_PAGEDOWN
0x27, //SDLK_RIGHT
0x25, //SDLK_LEFT
0x28, //SDLK_DOWN
0x26, //SDLK_UP
};
static const short keyCodes5[] = {
0xA2, //SDLK_LCTRL
0xA0, //SDLK_LSHIFT
0xA4, //SDLK_LALT
0x5B, //SDLK_LGUI
0xA3, //SDLK_RCTRL
0xA1, //SDLK_RSHIFT
0xA5, //SDLK_RALT
0x5C, //SDLK_RGUI
};
void sdlinput_init(char* mappings);
int sdlinput_handle_event(SDL_Window* window, SDL_Event* event);
void sdlinput_rumble(unsigned short controller_id, unsigned short low_freq_motor, unsigned short high_freq_motor);

View File

@ -74,7 +74,7 @@ void loop_add_fd(int fd, FdHandler handler, int events) {
void loop_remove_fd(int fd) {
numFds--;
int fdindex;
int fdindex = numFds;
for (int i=0;i<=numFds;i++) {
if (fds[i].fd == fd) {

View File

@ -195,7 +195,7 @@ static void help() {
printf("\t-4k\t\t\tUse 3840x2160 resolution\n");
printf("\t-width <width>\t\tHorizontal resolution (default 1280)\n");
printf("\t-height <height>\tVertical resolution (default 720)\n");
#if defined(HAVE_PI) | defined(HAVE_MMAL)
#ifdef HAVE_EMBEDDED
printf("\t-rotate <angle>\tRotate display: 0/90/180/270 (default 0)\n");
#endif
printf("\t-fps <fps>\t\tSpecify the fps to use (default 60)\n");

View File

@ -202,6 +202,9 @@ AUDIO_RENDERER_CALLBACKS* platform_get_audio(enum platform system, char* audio_d
#ifdef HAVE_ALSA
return &audio_callbacks_alsa;
#endif
#ifdef __FreeBSD__
return &audio_callbacks_oss;
#endif
}
return NULL;
}

View File

@ -63,4 +63,4 @@ bool ensure_buf_size(void **buf, size_t *buf_size, size_t required_size) {
}
return true;
}
}

View File

@ -23,3 +23,4 @@
int write_bool(char *path, bool val);
int read_file(char *path, char *output, int output_len);
bool ensure_buf_size(void **buf, size_t *buf_size, size_t required_size);
bool has_fast_aes(void);

View File

@ -28,7 +28,6 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
@ -40,7 +39,7 @@
#include <rockchip/rk_mpi.h>
#define MAX_FRAMES 16
#define MAX_FRAMES 3
#define RK_H264 0x7
#define RK_H265 0x1000004
#define RK_AV1 0x1000008
@ -159,33 +158,34 @@ void *display_thread(void *param) {
while (!frm_eos) {
int _fb_id;
ret = pthread_mutex_lock(&mutex);
assert(!ret);
pthread_mutex_lock(&mutex);
while (fb_id == 0) {
pthread_cond_wait(&cond, &mutex);
assert(!ret);
if (fb_id == 0 && frm_eos) {
ret = pthread_mutex_unlock(&mutex);
assert(!ret);
pthread_mutex_unlock(&mutex);
return NULL;
}
}
_fb_id = fb_id;
fb_id = 0;
ret = pthread_mutex_unlock(&mutex);
assert(!ret);
pthread_mutex_unlock(&mutex);
if (atomic) {
// We may need to modeset to apply colorspace changes when toggling HDR
set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "FB_ID", _fb_id);
ret = drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
if (ret) {
perror("drmModeAtomicCommit");
}
} else {
ret = drmModeSetPlane(fd, plane_id, crtc_id, _fb_id, 0,
fb_x, fb_y, fb_width, fb_height,
0, 0, frm_width << 16, frm_height << 16);
if (ret) {
perror("drmModeSetPlane");
}
}
assert(!ret);
}
return NULL;
@ -248,10 +248,11 @@ void *frame_thread(void *param) {
dmcd.bpp = 8; // hor_stride is already adjusted for 10 vs 8 bit
dmcd.width = hor_stride;
dmcd.height = ver_stride * 2; // documentation say not v*2/3 but v*2 (additional info included)
do {
ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
assert(!ret);
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd);
if (ret) {
perror("drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB)");
exit(EXIT_FAILURE);
}
assert(dmcd.pitch == dmcd.width);
assert(dmcd.size == dmcd.pitch * dmcd.height);
frame_to_drm[i].handle = dmcd.handle;
@ -260,10 +261,11 @@ void *frame_thread(void *param) {
struct drm_prime_handle dph = {0};
dph.handle = dmcd.handle;
dph.fd = -1;
do {
ret = ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
assert(!ret);
ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph);
if (ret) {
perror("drmIoctl(DRM_IOCTL_PRIME_HANDLE_TO_FD)");
exit(EXIT_FAILURE);
}
MppBufferInfo info = {0};
info.type = MPP_BUFFER_TYPE_DRM;
info.size = dmcd.width * dmcd.height;
@ -281,7 +283,10 @@ void *frame_thread(void *param) {
offsets[1] = pitches[0] * ver_stride;
pitches[1] = dmcd.pitch;
ret = drmModeAddFB2(fd, frm_width, frm_height, pixel_format, handles, pitches, offsets, &frame_to_drm[i].fb_id, 0);
assert(!ret);
if (ret) {
perror("drmModeAddFB2");
exit(EXIT_FAILURE);
}
}
// register external frame group
ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_EXT_BUF_GROUP, mpi_frm_grp);
@ -318,14 +323,10 @@ void *frame_thread(void *param) {
}
assert(i != MAX_FRAMES);
// send DRM FB to display thread
ret = pthread_mutex_lock(&mutex);
assert(!ret);
pthread_mutex_lock(&mutex);
fb_id = frame_to_drm[i].fb_id;
ret = pthread_cond_signal(&cond);
assert(!ret);
ret = pthread_mutex_unlock(&mutex);
assert(!ret);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
} else {
fprintf(stderr, "Frame no buff\n");
}
@ -382,7 +383,10 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
}
resources = drmModeGetResources(fd);
assert(resources);
if (!resources) {
perror("drmModeGetResources");
return -1;
}
// find active monitor
for (i = 0; i < resources->count_connectors; ++i) {
@ -430,7 +434,10 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
for (i = 0; i < resources->count_crtcs; ++i) {
if (resources->crtcs[i] == encoder->crtc_id) {
crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
assert(crtc);
if (!crtc) {
perror("drmModeGetCrtc");
continue;
}
break;
}
}
@ -441,15 +448,25 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
uint32_t crtc_bit = (1 << i);
ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
assert(!ret);
if (ret) {
perror("drmSetClientCap(DRM_CLIENT_CAP_UNIVERSAL_PLANES)");
}
if (atomic) {
ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
assert(!ret);
drm_request = drmModeAtomicAlloc();
assert(drm_request);
if (ret) {
perror("drmSetClientCap(DRM_CLIENT_CAP_ATOMIC)");
atomic = false;
}
else {
drm_request = drmModeAtomicAlloc();
assert(drm_request);
}
}
plane_resources = drmModeGetPlaneResources(fd);
assert(plane_resources);
if (!plane_resources) {
perror("drmModeGetPlaneResources");
return -1;
}
// search for OVERLAY (for active connector, unused, NV12 support)
for (i = 0; i < plane_resources->count_planes; i++) {
@ -487,6 +504,7 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
}
plane_props[j] = prop;
if (!strcmp(prop->name, "type") && (props->prop_values[j] == DRM_PLANE_TYPE_OVERLAY ||
props->prop_values[j] == DRM_PLANE_TYPE_CURSOR ||
props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY)) {
plane_id = ovr->plane_id;
}
@ -504,7 +522,29 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
}
drmModeFreePlane(ovr);
}
assert(plane_id);
if (!plane_id) {
fprintf(stderr, "Unable to find suitable plane\n");
return -1;
}
// DRM defines rotation in degrees counter-clockwise while we define
// rotation in degrees clockwise, so we swap the 90 and 270 cases
int displayRotation = drFlags & DISPLAY_ROTATE_MASK;
switch (displayRotation) {
case DISPLAY_ROTATE_90:
set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_270);
break;
case DISPLAY_ROTATE_180:
set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_180);
break;
case DISPLAY_ROTATE_270:
set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_90);
break;
default:
set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_0);
break;
}
// hide cursor by move in left lower corner
drmModeMoveCursor(fd, crtc_id, 0, crtc_height);
@ -537,15 +577,11 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte
ret = mpi_api->control(mpi_ctx, MPP_SET_OUTPUT_BLOCK, &param);
assert(!ret);
ret = pthread_mutex_init(&mutex, NULL);
assert(!ret);
ret = pthread_cond_init(&cond, NULL);
assert(!ret);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
ret = pthread_create(&tid_frame, NULL, frame_thread, NULL);
assert(!ret);
ret = pthread_create(&tid_display, NULL, display_thread, NULL);
assert(!ret);
pthread_create(&tid_frame, NULL, frame_thread, NULL);
pthread_create(&tid_display, NULL, display_thread, NULL);
return 0;
}
@ -556,26 +592,19 @@ void rk_cleanup() {
int ret;
frm_eos = 1;
ret = pthread_mutex_lock(&mutex);
assert(!ret);
ret = pthread_cond_signal(&cond);
assert(!ret);
ret = pthread_mutex_unlock(&mutex);
assert(!ret);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
ret = pthread_join(tid_display, NULL);
assert(!ret);
pthread_join(tid_display, NULL);
ret = pthread_cond_destroy(&cond);
assert(!ret);
ret = pthread_mutex_destroy(&mutex);
assert(!ret);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
ret = mpi_api->reset(mpi_ctx);
assert(!ret);
ret = pthread_join(tid_frame, NULL);
assert(!ret);
pthread_join(tid_frame, NULL);
if (mpi_frm_grp) {
ret = mpp_buffer_group_put(mpi_frm_grp);
@ -583,13 +612,15 @@ void rk_cleanup() {
mpi_frm_grp = NULL;
for (i = 0; i < MAX_FRAMES; i++) {
ret = drmModeRmFB(fd, frame_to_drm[i].fb_id);
assert(!ret);
if (ret) {
perror("drmModeRmFB");
}
struct drm_mode_destroy_dumb dmdd = {0};
dmdd.handle = frame_to_drm[i].handle;
do {
ret = ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
assert(!ret);
ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd);
if (ret) {
perror("drmIoctl(DRM_IOCTL_MODE_DESTROY_DUMB)");
}
}
}

@ -1 +1 @@
Subproject commit dbcf31a6709ec8354b5963b1bb411721e07bd846
Subproject commit ae51c9942f0d985b2161d6b22986f041fc98ce5c

@ -1 +1 @@
Subproject commit d457fbb48714d4ce79de2594180dfd73bc5f070c
Subproject commit 8af4562af672dd6b9ed28553ead172984fd9a683