diff --git a/.gitmodules b/.gitmodules index 92820c24..36d5dfe6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,19 +1,3 @@ -[submodule "third-party/moonlight-common-c"] - path = third-party/moonlight-common-c - url = https://github.com/moonlight-stream/moonlight-common-c.git - branch = master -[submodule "third-party/Simple-Web-Server"] - path = third-party/Simple-Web-Server - url = https://gitlab.com/eidheim/Simple-Web-Server.git - branch = master -[submodule "third-party/ViGEmClient"] - path = third-party/ViGEmClient - url = https://github.com/nefarius/ViGEmClient - branch = master -[submodule "third-party/miniupnp"] - path = third-party/miniupnp - url = https://github.com/miniupnp/miniupnp - branch = master [submodule "third-party/nv-codec-headers"] path = third-party/nv-codec-headers url = https://github.com/FFmpeg/nv-codec-headers @@ -42,14 +26,6 @@ path = third-party/ffmpeg-macos-aarch64 url = https://github.com/LizardByte/build-deps branch = ffmpeg-macos-aarch64 -[submodule "third-party/nanors"] - path = third-party/nanors - url = https://github.com/sleepybishop/nanors.git - branch = master -[submodule "third-party/tray"] - path = third-party/tray - url = https://github.com/LizardByte/tray - branch = master [submodule "third-party/nvapi-open-source-sdk"] path = third-party/nvapi-open-source-sdk url = https://github.com/LizardByte/nvapi-open-source-sdk diff --git a/cmake/compile_definitions/common.cmake b/cmake/compile_definitions/common.cmake index 07b46eac..91ff4e01 100644 --- a/cmake/compile_definitions/common.cmake +++ b/cmake/compile_definitions/common.cmake @@ -30,13 +30,6 @@ list(APPEND PLATFORM_TARGET_FILES ${NVENC_SOURCES}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SUNSHINE_TARGET_FILES - third-party/nanors/rs.c - third-party/nanors/rs.h - third-party/moonlight-common-c/src/Input.h - third-party/moonlight-common-c/src/Rtsp.h - third-party/moonlight-common-c/src/RtspParser.c - third-party/moonlight-common-c/src/Video.h - third-party/tray/tray.h src/cbs.cpp src/utility.h src/uuid.h @@ -59,8 +52,6 @@ set(SUNSHINE_TARGET_FILES src/stat_trackers.cpp ${PLATFORM_TARGET_FILES}) -set_source_files_properties(third-party/nanors/rs.c - PROPERTIES COMPILE_FLAGS "-include deps/obl/autoshim.h -ftree-vectorize") if(NOT SUNSHINE_ASSETS_DIR_DEF) set(SUNSHINE_ASSETS_DIR_DEF "${SUNSHINE_ASSETS_DIR}") @@ -74,9 +65,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories( SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third-party - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/enet/include - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/nanors - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/nanors/deps/obl ${FFMPEG_INCLUDE_DIRS} ${PLATFORM_INCLUDE_DIRS} ) @@ -91,9 +79,7 @@ else() endif() list(APPEND SUNSHINE_EXTERNAL_LIBRARIES - libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} - enet opus ${FFMPEG_LIBRARIES} ${Boost_LIBRARIES} diff --git a/cmake/compile_definitions/macos.cmake b/cmake/compile_definitions/macos.cmake index f2f2445f..50fba2ff 100644 --- a/cmake/compile_definitions/macos.cmake +++ b/cmake/compile_definitions/macos.cmake @@ -42,6 +42,4 @@ set(PLATFORM_TARGET_FILES if(SUNSHINE_ENABLE_TRAY) list(APPEND SUNSHINE_EXTERNAL_LIBRARIES ${COCOA}) - list(APPEND PLATFORM_TARGET_FILES - third-party/tray/tray_darwin.m) endif() diff --git a/cmake/compile_definitions/windows.cmake b/cmake/compile_definitions/windows.cmake index 25e4e932..59af591f 100644 --- a/cmake/compile_definitions/windows.cmake +++ b/cmake/compile_definitions/windows.cmake @@ -21,13 +21,6 @@ file(GLOB NVPREFS_FILES CONFIGURE_DEPENDS "src/platform/windows/nvprefs/*.cpp" "src/platform/windows/nvprefs/*.h") -# vigem -include_directories(SYSTEM third-party/ViGEmClient/include) -set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp - PROPERTIES COMPILE_DEFINITIONS "UNICODE=1;ERROR_INVALID_DEVICE_OBJECT_PARAMETER=650") -set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp - PROPERTIES COMPILE_FLAGS "-Wno-unknown-pragmas -Wno-misleading-indentation -Wno-class-memaccess") - # sunshine icon if(NOT DEFINED SUNSHINE_ICON_PATH) set(SUNSHINE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sunshine.ico") @@ -44,11 +37,6 @@ set(PLATFORM_TARGET_FILES src/platform/windows/display_vram.cpp src/platform/windows/display_ram.cpp src/platform/windows/audio.cpp - third-party/ViGEmClient/src/ViGEmClient.cpp - third-party/ViGEmClient/include/ViGEm/Client.h - third-party/ViGEmClient/include/ViGEm/Common.h - third-party/ViGEmClient/include/ViGEm/Util.h - third-party/ViGEmClient/include/ViGEm/km/BusShared.h ${NVPREFS_FILES}) set(OPENSSL_LIBRARIES @@ -68,9 +56,4 @@ list(PREPEND PLATFORM_LIBRARIES userenv synchronization.lib avrt - ${CURL_STATIC_LIBRARIES}) - -if(SUNSHINE_ENABLE_TRAY) - list(APPEND PLATFORM_TARGET_FILES - third-party/tray/tray_windows.c) -endif() + ${CURL_STATIC_LIBRARIES}) \ No newline at end of file diff --git a/cmake/dependencies/common.cmake b/cmake/dependencies/common.cmake index 9bc7c56c..eabb166b 100644 --- a/cmake/dependencies/common.cmake +++ b/cmake/dependencies/common.cmake @@ -1,22 +1,6 @@ # load common dependencies # this file will also load platform specific dependencies -# submodules -# moonlight common library -set(ENET_NO_INSTALL ON CACHE BOOL "Don't install any libraries build for enet") -add_subdirectory(third-party/moonlight-common-c/enet) - -# web server -add_subdirectory(third-party/Simple-Web-Server) - -# miniupnp -set(UPNPC_BUILD_SHARED OFF CACHE BOOL "No shared libraries") -set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Don't build tests for miniupnpc") -set(UPNPC_BUILD_SAMPLE OFF CACHE BOOL "Don't build samples for miniupnpc") -set(UPNPC_NO_INSTALL ON CACHE BOOL "Don't install any libraries build for miniupnpc") -add_subdirectory(third-party/miniupnp/miniupnpc) -include_directories(SYSTEM third-party/miniupnp/miniupnpc/include) - # ffmpeg pre-compiled binaries if(WIN32) if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") diff --git a/src/main.cpp b/src/main.cpp index 9c856083..b4f51f12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,6 @@ extern "C" { #include -#include #ifdef _WIN32 #include @@ -260,9 +259,6 @@ Init( // Unload dynamic library to survive driver reinstallation nvprefs_instance.unload(); } - - // Wait as long as possible to terminate Sunshine.exe during logoff/shutdown - SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY); #endif @@ -276,7 +272,6 @@ Init( } BOOST_LOG(error) << "Hello from thinkmay."sv; - reed_solomon_init(); } diff --git a/src/platform/common.h b/src/platform/common.h index ed73f599..d9e67629 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -16,9 +16,29 @@ #include "src/video_colorspace.h" extern "C" { -#include } +typedef struct _SS_HDR_METADATA { + // RGB order + struct { + uint16_t x; // Normalized to 50,000 + uint16_t y; // Normalized to 50,000 + } displayPrimaries[3]; + struct { + uint16_t x; // Normalized to 50,000 + uint16_t y; // Normalized to 50,000 + } whitePoint; + + uint16_t maxDisplayLuminance; // Nits + uint16_t minDisplayLuminance; // 1/10000th of a nit + + // These are content-specific values which may not be available for all hosts. + uint16_t maxContentLightLevel; // Nits + uint16_t maxFrameAverageLightLevel; // Nits + + // These are display-specific values which may not be available for all hosts. + uint16_t maxFullFrameLuminance; // Nits +} SS_HDR_METADATA, *PSS_HDR_METADATA; struct sockaddr; struct AVFrame; struct AVBufferRef; @@ -523,15 +543,13 @@ namespace platf { virtual ~audio_control_t() = default; }; - void - freeInput(void *); + std::filesystem::path appdata(); - std::string - get_mac_address(const std::string_view &address); + std::string from_sockaddr(const sockaddr *const); @@ -569,14 +587,7 @@ namespace platf { void adjust_thread_priority(thread_priority_e priority); - // Allow OS-specific actions to be taken to prepare for streaming - void - streaming_will_start(); - void - streaming_will_stop(); - void - restart(); struct batched_send_info_t { const char *buffer; @@ -610,52 +621,9 @@ namespace platf { std::unique_ptr enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type); - /** - * @brief Open a url in the default web browser. - * @param url The url to open. - */ - void - open_url(const std::string &url); - - typedef deinit_t client_input_t; - - /** - * @brief Sends a touch event to the OS. - * @param input The client-specific input context. - * @param touch_port The current viewport for translating to screen coordinates. - * @param touch The touch event. - */ - void - touch(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch); - - /** - * @brief Sends a pen event to the OS. - * @param input The client-specific input context. - * @param touch_port The current viewport for translating to screen coordinates. - * @param pen The pen event. - */ - void - pen(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen); - - - /** - * @brief Returns the supported platform capabilities to advertise to the client. - * @return Capability flags. - */ - platform_caps::caps_t - get_capabilities(); - -#define SERVICE_NAME "Sunshine" -#define SERVICE_TYPE "_nvstream._tcp" - - namespace publish { - [[nodiscard]] std::unique_ptr - start(); - } - [[nodiscard]] std::unique_ptr init(); } // namespace platf diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index aee35b9e..2a36c2c5 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -182,73 +182,11 @@ namespace platf { } } - /** - * @brief Open a url in the default web browser. - * @param url The url to open. - */ - void - open_url(const std::string &url) { - // set working dir to user home directory - auto working_dir = boost::filesystem::path(std::getenv("HOME")); - std::string cmd = R"(xdg-open ")" + url + R"(")"; - - boost::process::environment _env = boost::this_process::environment(); - std::error_code ec; - auto child = run_command(false, false, cmd, working_dir, _env, nullptr, ec, nullptr); - if (ec) { - BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message(); - } - else { - BOOST_LOG(info) << "Opened url ["sv << url << "]"sv; - child.detach(); - } - } - void adjust_thread_priority(thread_priority_e priority) { // Unimplemented } - void - streaming_will_start() { - // Nothing to do - } - - void - streaming_will_stop() { - // Nothing to do - } - - void - restart_on_exit() { - char executable[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", executable, PATH_MAX - 1); - if (len == -1) { - BOOST_LOG(fatal) << "readlink() failed: "sv << errno; - return; - } - executable[len] = '\0'; - - // ASIO doesn't use O_CLOEXEC, so we have to close all fds ourselves - int openmax = (int) sysconf(_SC_OPEN_MAX); - for (int fd = STDERR_FILENO + 1; fd < openmax; fd++) { - close(fd); - } - - // Re-exec ourselves with the same arguments - if (execv(executable, lifetime::get_argv()) < 0) { - BOOST_LOG(fatal) << "execv() failed: "sv << errno; - return; - } - } - - void - restart() { - // Gracefully clean up and restart ourselves instead of exiting - atexit(restart_on_exit); - lifetime::exit_sunshine(0, true); - } - struct sockaddr_in to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) { struct sockaddr_in saddr_v4 = {}; diff --git a/src/platform/linux/publish.cpp b/src/platform/linux/publish.cpp deleted file mode 100644 index e83bfb70..00000000 --- a/src/platform/linux/publish.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/** - * @file src/platform/linux/publish.cpp - * @brief todo - * @note Adapted from https://www.avahi.org/doxygen/html/client-publish-service_8c-example.html - * @todo Use a common file for this and src/platform/macos/publish.cpp - */ -#include - -#include "misc.h" -#include "src/main.h" -#include "src/nvhttp.h" -#include "src/platform/common.h" -#include "src/utility.h" - -using namespace std::literals; - -namespace avahi { - - /** - * @brief Error codes used by avahi. - */ - enum err_e { - OK = 0, /**< OK */ - ERR_FAILURE = -1, /**< Generic error code */ - ERR_BAD_STATE = -2, /**< Object was in a bad state */ - ERR_INVALID_HOST_NAME = -3, /**< Invalid host name */ - ERR_INVALID_DOMAIN_NAME = -4, /**< Invalid domain name */ - ERR_NO_NETWORK = -5, /**< No suitable network protocol available */ - ERR_INVALID_TTL = -6, /**< Invalid DNS TTL */ - ERR_IS_PATTERN = -7, /**< RR key is pattern */ - ERR_COLLISION = -8, /**< Name collision */ - ERR_INVALID_RECORD = -9, /**< Invalid RR */ - - ERR_INVALID_SERVICE_NAME = -10, /**< Invalid service name */ - ERR_INVALID_SERVICE_TYPE = -11, /**< Invalid service type */ - ERR_INVALID_PORT = -12, /**< Invalid port number */ - ERR_INVALID_KEY = -13, /**< Invalid key */ - ERR_INVALID_ADDRESS = -14, /**< Invalid address */ - ERR_TIMEOUT = -15, /**< Timeout reached */ - ERR_TOO_MANY_CLIENTS = -16, /**< Too many clients */ - ERR_TOO_MANY_OBJECTS = -17, /**< Too many objects */ - ERR_TOO_MANY_ENTRIES = -18, /**< Too many entries */ - ERR_OS = -19, /**< OS error */ - - ERR_ACCESS_DENIED = -20, /**< Access denied */ - ERR_INVALID_OPERATION = -21, /**< Invalid operation */ - ERR_DBUS_ERROR = -22, /**< An unexpected D-Bus error occurred */ - ERR_DISCONNECTED = -23, /**< Daemon connection failed */ - ERR_NO_MEMORY = -24, /**< Memory exhausted */ - ERR_INVALID_OBJECT = -25, /**< The object passed to this function was invalid */ - ERR_NO_DAEMON = -26, /**< Daemon not running */ - ERR_INVALID_INTERFACE = -27, /**< Invalid interface */ - ERR_INVALID_PROTOCOL = -28, /**< Invalid protocol */ - ERR_INVALID_FLAGS = -29, /**< Invalid flags */ - - ERR_NOT_FOUND = -30, /**< Not found */ - ERR_INVALID_CONFIG = -31, /**< Configuration error */ - ERR_VERSION_MISMATCH = -32, /**< Version mismatch */ - ERR_INVALID_SERVICE_SUBTYPE = -33, /**< Invalid service subtype */ - ERR_INVALID_PACKET = -34, /**< Invalid packet */ - ERR_INVALID_DNS_ERROR = -35, /**< Invalid DNS return code */ - ERR_DNS_FORMERR = -36, /**< DNS Error: Form error */ - ERR_DNS_SERVFAIL = -37, /**< DNS Error: Server Failure */ - ERR_DNS_NXDOMAIN = -38, /**< DNS Error: No such domain */ - ERR_DNS_NOTIMP = -39, /**< DNS Error: Not implemented */ - - ERR_DNS_REFUSED = -40, /**< DNS Error: Operation refused */ - ERR_DNS_YXDOMAIN = -41, - ERR_DNS_YXRRSET = -42, - ERR_DNS_NXRRSET = -43, - ERR_DNS_NOTAUTH = -44, /**< DNS Error: Not authorized */ - ERR_DNS_NOTZONE = -45, - ERR_INVALID_RDATA = -46, /**< Invalid RDATA */ - ERR_INVALID_DNS_CLASS = -47, /**< Invalid DNS class */ - ERR_INVALID_DNS_TYPE = -48, /**< Invalid DNS type */ - ERR_NOT_SUPPORTED = -49, /**< Not supported */ - - ERR_NOT_PERMITTED = -50, /**< Operation not permitted */ - ERR_INVALID_ARGUMENT = -51, /**< Invalid argument */ - ERR_IS_EMPTY = -52, /**< Is empty */ - ERR_NO_CHANGE = -53, /**< The requested operation is invalid because it is redundant */ - - ERR_MAX = -54 - }; - - constexpr auto IF_UNSPEC = -1; - enum proto { - PROTO_INET = 0, /**< IPv4 */ - PROTO_INET6 = 1, /**< IPv6 */ - PROTO_UNSPEC = -1 /**< Unspecified/all protocol(s) */ - }; - - enum ServerState { - SERVER_INVALID, /**< Invalid state (initial) */ - SERVER_REGISTERING, /**< Host RRs are being registered */ - SERVER_RUNNING, /**< All host RRs have been established */ - SERVER_COLLISION, /**< There is a collision with a host RR. All host RRs have been withdrawn, the user should set a new host name via avahi_server_set_host_name() */ - SERVER_FAILURE /**< Some fatal failure happened, the server is unable to proceed */ - }; - - enum ClientState { - CLIENT_S_REGISTERING = SERVER_REGISTERING, /**< Server state: REGISTERING */ - CLIENT_S_RUNNING = SERVER_RUNNING, /**< Server state: RUNNING */ - CLIENT_S_COLLISION = SERVER_COLLISION, /**< Server state: COLLISION */ - CLIENT_FAILURE = 100, /**< Some kind of error happened on the client side */ - CLIENT_CONNECTING = 101 /**< We're still connecting. This state is only entered when AVAHI_CLIENT_NO_FAIL has been passed to avahi_client_new() and the daemon is not yet available. */ - }; - - enum EntryGroupState { - ENTRY_GROUP_UNCOMMITED, /**< The group has not yet been committed, the user must still call avahi_entry_group_commit() */ - ENTRY_GROUP_REGISTERING, /**< The entries of the group are currently being registered */ - ENTRY_GROUP_ESTABLISHED, /**< The entries have successfully been established */ - ENTRY_GROUP_COLLISION, /**< A name collision for one of the entries in the group has been detected, the entries have been withdrawn */ - ENTRY_GROUP_FAILURE /**< Some kind of failure happened, the entries have been withdrawn */ - }; - - enum ClientFlags { - CLIENT_IGNORE_USER_CONFIG = 1, /**< Don't read user configuration */ - CLIENT_NO_FAIL = 2 /**< Don't fail if the daemon is not available when avahi_client_new() is called, instead enter CLIENT_CONNECTING state and wait for the daemon to appear */ - }; - - /** - * @brief Flags for publishing functions. - */ - enum PublishFlags { - PUBLISH_UNIQUE = 1, /**< For raw records: The RRset is intended to be unique */ - PUBLISH_NO_PROBE = 2, /**< For raw records: Though the RRset is intended to be unique no probes shall be sent */ - PUBLISH_NO_ANNOUNCE = 4, /**< For raw records: Do not announce this RR to other hosts */ - PUBLISH_ALLOW_MULTIPLE = 8, /**< For raw records: Allow multiple local records of this type, even if they are intended to be unique */ - /** \cond fulldocs */ - PUBLISH_NO_REVERSE = 16, /**< For address records: don't create a reverse (PTR) entry */ - PUBLISH_NO_COOKIE = 32, /**< For service records: do not implicitly add the local service cookie to TXT data */ - /** \endcond */ - PUBLISH_UPDATE = 64, /**< Update existing records instead of adding new ones */ - /** \cond fulldocs */ - PUBLISH_USE_WIDE_AREA = 128, /**< Register the record using wide area DNS (i.e. unicast DNS update) */ - PUBLISH_USE_MULTICAST = 256 /**< Register the record using multicast DNS */ - /** \endcond */ - }; - - using IfIndex = int; - using Protocol = int; - - struct EntryGroup; - struct Poll; - struct SimplePoll; - struct Client; - - typedef void (*ClientCallback)(Client *, ClientState, void *userdata); - typedef void (*EntryGroupCallback)(EntryGroup *g, EntryGroupState state, void *userdata); - - typedef void (*free_fn)(void *); - - typedef Client *(*client_new_fn)(const Poll *poll_api, ClientFlags flags, ClientCallback callback, void *userdata, int *error); - typedef void (*client_free_fn)(Client *); - typedef char *(*alternative_service_name_fn)(char *); - - typedef Client *(*entry_group_get_client_fn)(EntryGroup *); - - typedef EntryGroup *(*entry_group_new_fn)(Client *, EntryGroupCallback, void *userdata); - typedef int (*entry_group_add_service_fn)( - EntryGroup *group, - IfIndex interface, - Protocol protocol, - PublishFlags flags, - const char *name, - const char *type, - const char *domain, - const char *host, - uint16_t port, - ...); - - typedef int (*entry_group_is_empty_fn)(EntryGroup *); - typedef int (*entry_group_reset_fn)(EntryGroup *); - typedef int (*entry_group_commit_fn)(EntryGroup *); - - typedef char *(*strdup_fn)(const char *); - typedef char *(*strerror_fn)(int); - typedef int (*client_errno_fn)(Client *); - - typedef Poll *(*simple_poll_get_fn)(SimplePoll *); - typedef int (*simple_poll_loop_fn)(SimplePoll *); - typedef void (*simple_poll_quit_fn)(SimplePoll *); - typedef SimplePoll *(*simple_poll_new_fn)(); - typedef void (*simple_poll_free_fn)(SimplePoll *); - - free_fn free; - client_new_fn client_new; - client_free_fn client_free; - alternative_service_name_fn alternative_service_name; - entry_group_get_client_fn entry_group_get_client; - entry_group_new_fn entry_group_new; - entry_group_add_service_fn entry_group_add_service; - entry_group_is_empty_fn entry_group_is_empty; - entry_group_reset_fn entry_group_reset; - entry_group_commit_fn entry_group_commit; - strdup_fn strdup; - strerror_fn strerror; - client_errno_fn client_errno; - simple_poll_get_fn simple_poll_get; - simple_poll_loop_fn simple_poll_loop; - simple_poll_quit_fn simple_poll_quit; - simple_poll_new_fn simple_poll_new; - simple_poll_free_fn simple_poll_free; - - int - init_common() { - static void *handle { nullptr }; - static bool funcs_loaded = false; - - if (funcs_loaded) return 0; - - if (!handle) { - handle = dyn::handle({ "libavahi-common.so.3", "libavahi-common.so" }); - if (!handle) { - return -1; - } - } - - std::vector> funcs { - { (dyn::apiproc *) &alternative_service_name, "avahi_alternative_service_name" }, - { (dyn::apiproc *) &free, "avahi_free" }, - { (dyn::apiproc *) &strdup, "avahi_strdup" }, - { (dyn::apiproc *) &strerror, "avahi_strerror" }, - { (dyn::apiproc *) &simple_poll_get, "avahi_simple_poll_get" }, - { (dyn::apiproc *) &simple_poll_loop, "avahi_simple_poll_loop" }, - { (dyn::apiproc *) &simple_poll_quit, "avahi_simple_poll_quit" }, - { (dyn::apiproc *) &simple_poll_new, "avahi_simple_poll_new" }, - { (dyn::apiproc *) &simple_poll_free, "avahi_simple_poll_free" }, - }; - - if (dyn::load(handle, funcs)) { - return -1; - } - - funcs_loaded = true; - return 0; - } - - int - init_client() { - if (init_common()) { - return -1; - } - - static void *handle { nullptr }; - static bool funcs_loaded = false; - - if (funcs_loaded) return 0; - - if (!handle) { - handle = dyn::handle({ "libavahi-client.so.3", "libavahi-client.so" }); - if (!handle) { - return -1; - } - } - - std::vector> funcs { - { (dyn::apiproc *) &client_new, "avahi_client_new" }, - { (dyn::apiproc *) &client_free, "avahi_client_free" }, - { (dyn::apiproc *) &entry_group_get_client, "avahi_entry_group_get_client" }, - { (dyn::apiproc *) &entry_group_new, "avahi_entry_group_new" }, - { (dyn::apiproc *) &entry_group_add_service, "avahi_entry_group_add_service" }, - { (dyn::apiproc *) &entry_group_is_empty, "avahi_entry_group_is_empty" }, - { (dyn::apiproc *) &entry_group_reset, "avahi_entry_group_reset" }, - { (dyn::apiproc *) &entry_group_commit, "avahi_entry_group_commit" }, - { (dyn::apiproc *) &client_errno, "avahi_client_errno" }, - }; - - if (dyn::load(handle, funcs)) { - return -1; - } - - funcs_loaded = true; - return 0; - } -} // namespace avahi - -namespace platf::publish { - - template - void - free(T *p) { - avahi::free(p); - } - - template - using ptr_t = util::safe_ptr>; - using client_t = util::dyn_safe_ptr; - using poll_t = util::dyn_safe_ptr; - - avahi::EntryGroup *group = nullptr; - - poll_t poll; - client_t client; - - ptr_t name; - - void - create_services(avahi::Client *c); - - void - entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, void *) { - group = g; - - switch (state) { - case avahi::ENTRY_GROUP_ESTABLISHED: - BOOST_LOG(info) << "Avahi service " << name.get() << " successfully established."; - break; - case avahi::ENTRY_GROUP_COLLISION: - name.reset(avahi::alternative_service_name(name.get())); - - BOOST_LOG(info) << "Avahi service name collision, renaming service to " << name.get(); - - create_services(avahi::entry_group_get_client(g)); - break; - case avahi::ENTRY_GROUP_FAILURE: - BOOST_LOG(error) << "Avahi entry group failure: " << avahi::strerror(avahi::client_errno(avahi::entry_group_get_client(g))); - avahi::simple_poll_quit(poll.get()); - break; - case avahi::ENTRY_GROUP_UNCOMMITED: - case avahi::ENTRY_GROUP_REGISTERING:; - } - } - - void - create_services(avahi::Client *c) { - int ret; - - auto fg = util::fail_guard([]() { - avahi::simple_poll_quit(poll.get()); - }); - - if (!group) { - if (!(group = avahi::entry_group_new(c, entry_group_callback, nullptr))) { - BOOST_LOG(error) << "avahi::entry_group_new() failed: "sv << avahi::strerror(avahi::client_errno(c)); - return; - } - } - - if (avahi::entry_group_is_empty(group)) { - BOOST_LOG(info) << "Adding avahi service "sv << name.get(); - - ret = avahi::entry_group_add_service( - group, - avahi::IF_UNSPEC, avahi::PROTO_UNSPEC, - avahi::PublishFlags(0), - name.get(), - SERVICE_TYPE, - nullptr, nullptr, - map_port(nvhttp::PORT_HTTP), - nullptr); - - if (ret < 0) { - if (ret == avahi::ERR_COLLISION) { - // A service name collision with a local service happened. Let's pick a new name - name.reset(avahi::alternative_service_name(name.get())); - BOOST_LOG(info) << "Service name collision, renaming service to "sv << name.get(); - - avahi::entry_group_reset(group); - - create_services(c); - - fg.disable(); - return; - } - - BOOST_LOG(error) << "Failed to add "sv << SERVICE_TYPE << " service: "sv << avahi::strerror(ret); - return; - } - - ret = avahi::entry_group_commit(group); - if (ret < 0) { - BOOST_LOG(error) << "Failed to commit entry group: "sv << avahi::strerror(ret); - return; - } - } - - fg.disable(); - } - - void - client_callback(avahi::Client *c, avahi::ClientState state, void *) { - switch (state) { - case avahi::CLIENT_S_RUNNING: - create_services(c); - break; - case avahi::CLIENT_FAILURE: - BOOST_LOG(error) << "Client failure: "sv << avahi::strerror(avahi::client_errno(c)); - avahi::simple_poll_quit(poll.get()); - break; - case avahi::CLIENT_S_COLLISION: - case avahi::CLIENT_S_REGISTERING: - if (group) - avahi::entry_group_reset(group); - break; - case avahi::CLIENT_CONNECTING:; - } - } - - class deinit_t: public ::platf::deinit_t { - public: - std::thread poll_thread; - - deinit_t(std::thread poll_thread): - poll_thread { std::move(poll_thread) } {} - - ~deinit_t() override { - if (avahi::simple_poll_quit && poll) { - avahi::simple_poll_quit(poll.get()); - } - - if (poll_thread.joinable()) { - poll_thread.join(); - } - } - }; - - [[nodiscard]] std::unique_ptr<::platf::deinit_t> - start() { - if (avahi::init_client()) { - return nullptr; - } - - int avhi_error; - - poll.reset(avahi::simple_poll_new()); - if (!poll) { - BOOST_LOG(error) << "Failed to create simple poll object."sv; - return nullptr; - } - - name.reset(avahi::strdup(SERVICE_NAME)); - - client.reset( - avahi::client_new(avahi::simple_poll_get(poll.get()), avahi::ClientFlags(0), client_callback, nullptr, &avhi_error)); - - if (!client) { - BOOST_LOG(error) << "Failed to create client: "sv << avahi::strerror(avhi_error); - return nullptr; - } - - return std::make_unique(std::thread { avahi::simple_poll_loop, poll.get() }); - } -} // namespace platf::publish diff --git a/src/platform/macos/misc.mm b/src/platform/macos/misc.mm index b1d7eac7..c40a700f 100644 --- a/src/platform/macos/misc.mm +++ b/src/platform/macos/misc.mm @@ -128,45 +128,6 @@ namespace platf { return { port, std::string { data } }; } - std::string - get_mac_address(const std::string_view &address) { - auto ifaddrs = get_ifaddrs(); - - for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) { - if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) { - BOOST_LOG(verbose) << "Looking for MAC of "sv << pos->ifa_name; - - struct ifaddrs *ifap, *ifaptr; - unsigned char *ptr; - std::string mac_address; - - if (getifaddrs(&ifap) == 0) { - for (ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) { - if (!strcmp((ifaptr)->ifa_name, pos->ifa_name) && (((ifaptr)->ifa_addr)->sa_family == AF_LINK)) { - ptr = (unsigned char *) LLADDR((struct sockaddr_dl *) (ifaptr)->ifa_addr); - char buff[100]; - - snprintf(buff, sizeof(buff), "%02x:%02x:%02x:%02x:%02x:%02x", - *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5)); - mac_address = buff; - break; - } - } - - freeifaddrs(ifap); - - if (ifaptr != NULL) { - BOOST_LOG(verbose) << "Found MAC of "sv << pos->ifa_name << ": "sv << mac_address; - return mac_address; - } - } - } - } - - BOOST_LOG(warning) << "Unable to find MAC address for "sv << address; - return "00:00:00:00:00:00"s; - } - bp::child run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) { if (!group) { @@ -187,64 +148,13 @@ namespace platf { } } - /** - * @brief Open a url in the default web browser. - * @param url The url to open. - */ - void - open_url(const std::string &url) { - boost::filesystem::path working_dir; - std::string cmd = R"(open ")" + url + R"(")"; - boost::process::environment _env = boost::this_process::environment(); - std::error_code ec; - auto child = run_command(false, false, cmd, working_dir, _env, nullptr, ec, nullptr); - if (ec) { - BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message(); - } - else { - BOOST_LOG(info) << "Opened url ["sv << url << "]"sv; - child.detach(); - } - } void adjust_thread_priority(thread_priority_e priority) { // Unimplemented } - void - streaming_will_start() { - // Nothing to do - } - - void - streaming_will_stop() { - // Nothing to do - } - - void - restart_on_exit() { - char executable[2048]; - uint32_t size = sizeof(executable); - if (_NSGetExecutablePath(executable, &size) < 0) { - BOOST_LOG(fatal) << "NSGetExecutablePath() failed: "sv << errno; - return; - } - - // ASIO doesn't use O_CLOEXEC, so we have to close all fds ourselves - int openmax = (int) sysconf(_SC_OPEN_MAX); - for (int fd = STDERR_FILENO + 1; fd < openmax; fd++) { - close(fd); - } - } - - void - restart() { - // Gracefully clean up and restart ourselves instead of exiting - atexit(restart_on_exit); - } - struct sockaddr_in to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) { struct sockaddr_in saddr_v4 = {}; diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 2d00c52f..262e955f 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -128,40 +128,6 @@ namespace platf { return { port, std::string { data } }; } - adapteraddrs_t - get_adapteraddrs() { - adapteraddrs_t info { nullptr }; - ULONG size = 0; - - while (GetAdaptersAddresses(AF_UNSPEC, 0, nullptr, info.get(), &size) == ERROR_BUFFER_OVERFLOW) { - info.reset((PIP_ADAPTER_ADDRESSES) malloc(size)); - } - - return info; - } - - std::string - get_mac_address(const std::string_view &address) { - adapteraddrs_t info = get_adapteraddrs(); - for (auto adapter_pos = info.get(); adapter_pos != nullptr; adapter_pos = adapter_pos->Next) { - for (auto addr_pos = adapter_pos->FirstUnicastAddress; addr_pos != nullptr; addr_pos = addr_pos->Next) { - if (adapter_pos->PhysicalAddressLength != 0 && address == from_sockaddr(addr_pos->Address.lpSockaddr)) { - std::stringstream mac_addr; - mac_addr << std::hex; - for (int i = 0; i < adapter_pos->PhysicalAddressLength; i++) { - if (i > 0) { - mac_addr << ':'; - } - mac_addr << std::setw(2) << std::setfill('0') << (int) adapter_pos->PhysicalAddress[i]; - } - return mac_addr.str(); - } - } - } - BOOST_LOG(warning) << "Unable to find MAC address for "sv << address; - return "00:00:00:00:00:00"s; - } - HDESK syncThreadDesktop() { auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL); @@ -679,30 +645,6 @@ namespace platf { return create_boost_child_from_results(ret, cmd, ec, process_info); } - /** - * @brief Open a url in the default web browser. - * @param url The url to open. - */ - void - open_url(const std::string &url) { - // set working dir to Windows system directory - auto working_dir = boost::filesystem::path(std::getenv("SystemRoot")); - - boost::process::environment _env = boost::this_process::environment(); - std::error_code ec; - - // Launch this as a non-interactive non-elevated command to avoid an extra console window - std::string cmd = R"(cmd /C "start )" + url + R"(")"; - auto child = run_command(false, false, cmd, working_dir, _env, nullptr, ec, nullptr); - if (ec) { - BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message(); - } - else { - BOOST_LOG(info) << "Opened url ["sv << url << "]"sv; - child.detach(); - } - } - void adjust_thread_priority(thread_priority_e priority) { int win32_priority; @@ -731,187 +673,8 @@ namespace platf { } } - void - streaming_will_start() { - static std::once_flag load_wlanapi_once_flag; - std::call_once(load_wlanapi_once_flag, []() { - // wlanapi.dll is not installed by default on Windows Server, so we load it dynamically - HMODULE wlanapi = LoadLibraryExA("wlanapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (!wlanapi) { - BOOST_LOG(debug) << "wlanapi.dll is not available on this OS"sv; - return; - } - fn_WlanOpenHandle = (decltype(fn_WlanOpenHandle)) GetProcAddress(wlanapi, "WlanOpenHandle"); - fn_WlanCloseHandle = (decltype(fn_WlanCloseHandle)) GetProcAddress(wlanapi, "WlanCloseHandle"); - fn_WlanFreeMemory = (decltype(fn_WlanFreeMemory)) GetProcAddress(wlanapi, "WlanFreeMemory"); - fn_WlanEnumInterfaces = (decltype(fn_WlanEnumInterfaces)) GetProcAddress(wlanapi, "WlanEnumInterfaces"); - fn_WlanSetInterface = (decltype(fn_WlanSetInterface)) GetProcAddress(wlanapi, "WlanSetInterface"); - if (!fn_WlanOpenHandle || !fn_WlanCloseHandle || !fn_WlanFreeMemory || !fn_WlanEnumInterfaces || !fn_WlanSetInterface) { - BOOST_LOG(error) << "wlanapi.dll is missing exports?"sv; - - fn_WlanOpenHandle = nullptr; - fn_WlanCloseHandle = nullptr; - fn_WlanFreeMemory = nullptr; - fn_WlanEnumInterfaces = nullptr; - fn_WlanSetInterface = nullptr; - - FreeLibrary(wlanapi); - return; - } - }); - - // Enable MMCSS scheduling for DWM - DwmEnableMMCSS(true); - - // Reduce timer period to 1ms - timeBeginPeriod(1); - - // Promote ourselves to high priority class - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - // Modify NVIDIA control panel settings again, in case they have been changed externally since sunshine launch - if (nvprefs_instance.load()) { - if (!nvprefs_instance.owning_undo_file()) { - nvprefs_instance.restore_from_and_delete_undo_file_if_exists(); - } - nvprefs_instance.modify_application_profile(); - nvprefs_instance.modify_global_profile(); - nvprefs_instance.unload(); - } - - // Enable low latency mode on all connected WLAN NICs if wlanapi.dll is available - if (fn_WlanOpenHandle) { - DWORD negotiated_version; - - if (fn_WlanOpenHandle(WLAN_API_MAKE_VERSION(2, 0), nullptr, &negotiated_version, &wlan_handle) == ERROR_SUCCESS) { - PWLAN_INTERFACE_INFO_LIST wlan_interface_list; - - if (fn_WlanEnumInterfaces(wlan_handle, nullptr, &wlan_interface_list) == ERROR_SUCCESS) { - for (DWORD i = 0; i < wlan_interface_list->dwNumberOfItems; i++) { - if (wlan_interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected) { - // Enable media streaming mode for 802.11 wireless interfaces to reduce latency and - // unnecessary background scanning operations that cause packet loss and jitter. - // - // https://docs.microsoft.com/en-us/windows-hardware/drivers/network/oid-wdi-set-connection-quality - // https://docs.microsoft.com/en-us/previous-versions/windows/hardware/wireless/native-802-11-media-streaming - BOOL value = TRUE; - auto error = fn_WlanSetInterface(wlan_handle, &wlan_interface_list->InterfaceInfo[i].InterfaceGuid, - wlan_intf_opcode_media_streaming_mode, sizeof(value), &value, nullptr); - if (error == ERROR_SUCCESS) { - BOOST_LOG(info) << "WLAN interface "sv << i << " is now in low latency mode"sv; - } - } - } - - fn_WlanFreeMemory(wlan_interface_list); - } - else { - fn_WlanCloseHandle(wlan_handle, nullptr); - wlan_handle = NULL; - } - } - } - - // If there is no mouse connected, enable Mouse Keys to force the cursor to appear - if (!GetSystemMetrics(SM_MOUSEPRESENT)) { - BOOST_LOG(info) << "A mouse was not detected. Sunshine will enable Mouse Keys while streaming to force the mouse cursor to appear."; - - // Get the current state of Mouse Keys so we can restore it when streaming is over - previous_mouse_keys_state.cbSize = sizeof(previous_mouse_keys_state); - if (SystemParametersInfoW(SPI_GETMOUSEKEYS, 0, &previous_mouse_keys_state, 0)) { - MOUSEKEYS new_mouse_keys_state = {}; - - // Enable Mouse Keys - new_mouse_keys_state.cbSize = sizeof(new_mouse_keys_state); - new_mouse_keys_state.dwFlags = MKF_MOUSEKEYSON | MKF_AVAILABLE; - new_mouse_keys_state.iMaxSpeed = 10; - new_mouse_keys_state.iTimeToMaxSpeed = 1000; - if (SystemParametersInfoW(SPI_SETMOUSEKEYS, 0, &new_mouse_keys_state, 0)) { - // Remember to restore the previous settings when we stop streaming - enabled_mouse_keys = true; - } - else { - auto winerr = GetLastError(); - BOOST_LOG(warning) << "Unable to enable Mouse Keys: "sv << winerr; - } - } - else { - auto winerr = GetLastError(); - BOOST_LOG(warning) << "Unable to get current state of Mouse Keys: "sv << winerr; - } - } - } - - void - streaming_will_stop() { - // Demote ourselves back to normal priority class - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - - // End our 1ms timer request - timeEndPeriod(1); - - // Disable MMCSS scheduling for DWM - DwmEnableMMCSS(false); - - // Closing our WLAN client handle will undo our optimizations - if (wlan_handle != nullptr) { - fn_WlanCloseHandle(wlan_handle, nullptr); - wlan_handle = nullptr; - } - - // Restore Mouse Keys back to the previous settings if we turned it on - if (enabled_mouse_keys) { - enabled_mouse_keys = false; - if (!SystemParametersInfoW(SPI_SETMOUSEKEYS, 0, &previous_mouse_keys_state, 0)) { - auto winerr = GetLastError(); - BOOST_LOG(warning) << "Unable to restore original state of Mouse Keys: "sv << winerr; - } - } - } - - void - restart_on_exit() { - STARTUPINFOEXW startup_info {}; - startup_info.StartupInfo.cb = sizeof(startup_info); - - WCHAR executable[MAX_PATH]; - if (GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable)) == 0) { - auto winerr = GetLastError(); - BOOST_LOG(fatal) << "Failed to get Sunshine path: "sv << winerr; - return; - } - - PROCESS_INFORMATION process_info; - if (!CreateProcessW(executable, - GetCommandLineW(), - nullptr, - nullptr, - false, - CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, - nullptr, - nullptr, - (LPSTARTUPINFOW) &startup_info, - &process_info)) { - auto winerr = GetLastError(); - BOOST_LOG(fatal) << "Unable to restart Sunshine: "sv << winerr; - return; - } - - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - } - - void - restart() { - // If we're running standalone, we have to respawn ourselves via CreateProcess(). - // If we're running from the service, we should just exit and let it respawn us. - if (GetConsoleWindow() != NULL) { - // Avoid racing with the new process by waiting until we're exiting to start it. - atexit(restart_on_exit); - } - } SOCKADDR_IN to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) { diff --git a/third-party/Simple-Web-Server b/third-party/Simple-Web-Server deleted file mode 160000 index 2f29926d..00000000 --- a/third-party/Simple-Web-Server +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2f29926dbbcd8a0425064d98c24f37ac50bd0b5b diff --git a/third-party/ViGEmClient b/third-party/ViGEmClient deleted file mode 160000 index b66d02d5..00000000 --- a/third-party/ViGEmClient +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b66d02d57e32cc8595369c53418b843e958649b4 diff --git a/third-party/miniupnp b/third-party/miniupnp deleted file mode 160000 index e439318c..00000000 --- a/third-party/miniupnp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e439318cf782e30066d430f27a1365e013a5ab94 diff --git a/third-party/moonlight-common-c b/third-party/moonlight-common-c deleted file mode 160000 index f78f2135..00000000 --- a/third-party/moonlight-common-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f78f2135fa49e19855c2028b6865657d42d511f1 diff --git a/third-party/nanors b/third-party/nanors deleted file mode 160000 index 395e5ada..00000000 --- a/third-party/nanors +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 395e5ada44dd8d5974eaf6bb6b17f23406e3ca72 diff --git a/third-party/tray b/third-party/tray deleted file mode 160000 index 2664388b..00000000 --- a/third-party/tray +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2664388b0ed88234674a37f8cd569747522247b4