From f0532d7281014267ad581b51a2cf37e59f05831a Mon Sep 17 00:00:00 2001 From: ABeltramo Date: Sat, 8 Jul 2023 14:23:31 +0100 Subject: [PATCH 01/87] refactor: basic split between Core and Moonlight --- CMakeLists.txt | 20 +- Cargo.toml | 2 +- docker/wolf.Dockerfile | 4 +- src/audio/CMakeLists.txt | 32 --- src/core/CMakeLists.txt | 72 +++++++ .../gst-plugin-wayland-display/Cargo.toml | 0 .../rust/gst-plugin-wayland-display/build.rs | 0 .../gst-plugin-wayland-display/src/lib.rs | 0 .../gst-plugin-wayland-display/src/utils.rs | 0 .../src/waylandsrc/imp.rs | 0 .../src/waylandsrc/mod.rs | 0 .../rust/gst-wayland-display/CMakeLists.txt | 0 .../rust/gst-wayland-display/Cargo.toml | 0 .../include/waylanddisplay.h | 0 .../gst-wayland-display/resources/cursor.rgba | Bin .../resources/protocols/wayland-drm.xml | 0 .../gst-wayland-display/src/comp/focus.rs | 0 .../gst-wayland-display/src/comp/input.rs | 0 .../rust/gst-wayland-display/src/comp/mod.rs | 0 .../gst-wayland-display/src/comp/rendering.rs | 0 .../rust/gst-wayland-display/src/lib.rs | 0 .../rust/gst-wayland-display/src/utils/mod.rs | 0 .../gst-wayland-display/src/utils/target.rs | 0 .../src/wayland/handlers/compositor.rs | 0 .../src/wayland/handlers/data_device.rs | 0 .../src/wayland/handlers/dmabuf.rs | 0 .../src/wayland/handlers/mod.rs | 0 .../src/wayland/handlers/output.rs | 0 .../src/wayland/handlers/presentation.rs | 0 .../src/wayland/handlers/relative_pointer.rs | 0 .../src/wayland/handlers/seat.rs | 0 .../src/wayland/handlers/shm.rs | 0 .../src/wayland/handlers/viewporter.rs | 0 .../src/wayland/handlers/wl_drm.rs | 0 .../src/wayland/handlers/xdg.rs | 0 .../gst-wayland-display/src/wayland/mod.rs | 0 .../src/wayland/protocols/mod.rs | 0 .../src/wayland/protocols/wl_drm.rs | 0 src/core/src/core/api.hpp | 51 +++++ src/{audio/audio => core/src/core}/audio.hpp | 2 +- .../docker => core/src/core}/docker.hpp | 2 +- src/core/src/core/gstreamer.hpp | 139 +++++++++++++ src/{input/input => core/src/core}/input.hpp | 7 +- .../src/core}/virtual-display.hpp | 21 +- .../src/platforms/all}/docker/CMakeLists.txt | 3 +- .../platforms/all}/docker/docker/docker.cpp | 4 +- .../all}/docker/docker/formatters.hpp | 4 +- .../all}/docker/docker/json_formatters.hpp | 4 +- .../src/platforms/all}/helpers/CMakeLists.txt | 0 .../platforms/all}/helpers/helpers/logger.hpp | 0 .../platforms/all}/helpers/helpers/utils.hpp | 0 .../platforms/linux/pulseaudio/CMakeLists.txt | 24 +++ .../src/platforms/linux/pulseaudio}/pulse.cpp | 4 +- .../src/platforms/linux/uinput/CMakeLists.txt | 71 +++++++ .../src/platforms/linux/uinput}/keyboard.hpp | 2 +- .../src/platforms/linux/uinput}/uinput.cpp | 12 +- .../src/platforms/linux/uinput}/uinput.hpp | 4 +- .../virtual-display}/wayland-display.cpp | 8 +- .../src/platforms/unknown/audio.cpp} | 4 +- .../src}/platforms/unknown/input.cpp | 4 +- .../platforms/unknown/no-virtual-display.cpp | 2 +- src/input/CMakeLists.txt | 66 ------ .../CMakeLists.txt | 4 +- .../crypto/CMakeLists.txt | 7 +- .../crypto/crypto/crypto.hpp | 0 .../crypto/crypto/utils.hpp | 0 .../crypto/src/aes.hpp | 0 .../crypto/src/crypto.cpp | 0 .../crypto/src/sign.hpp | 0 .../crypto/src/utils.cpp | 0 .../crypto/src/x509.cpp | 0 .../moonlight.cpp | 0 .../moonlight/control.hpp | 38 +--- .../moonlight/data-structures.hpp | 0 .../moonlight/fec.hpp | 0 .../moonlight/protocol.hpp | 0 .../rtsp/parser.hpp | 0 src/{wolf => moonlight-server}/CMakeLists.txt | 15 +- .../control/control.cpp | 2 +- .../control/control.hpp | 0 .../gst-plugin/audio.hpp | 31 ++- .../gst-plugin/gstrtpmoonlightpay_audio.cpp | 4 +- .../gst-plugin/gstrtpmoonlightpay_audio.hpp | 0 .../gst-plugin/gstrtpmoonlightpay_video.cpp | 4 +- .../gst-plugin/gstrtpmoonlightpay_video.hpp | 0 .../gst-plugin/utils.hpp | 1 - .../gst-plugin/video.hpp | 41 +++- .../platforms/hw.hpp | 0 .../platforms/hw_linux.cpp | 0 .../platforms/hw_unknown.cpp | 0 .../rest/custom-https.cpp | 0 .../rest/endpoints.hpp | 1 + .../rest/helpers.hpp | 0 .../rest/html/pin.html | 0 .../rest/html/pin.include.html | 0 src/{wolf => moonlight-server}/rest/rest.hpp | 0 .../rest/servers.cpp | 0 .../rtp/udp-ping.cpp | 0 .../rtp/udp-ping.hpp | 0 .../rtsp/commands.hpp | 7 +- src/{wolf => moonlight-server}/rtsp/net.hpp | 0 .../runners/docker.hpp | 4 +- .../runners/process.cpp | 0 .../runners/process.hpp | 1 - .../state/config.hpp | 0 .../state/configTOML.cpp | 2 + .../state/data-structures.hpp | 6 +- .../state/default/config.include.toml | 0 .../state/default/config.v2.toml | 0 .../state/sessions.hpp | 0 .../streaming/data-structures.hpp | 50 +---- .../streaming/streaming.cpp | 192 ++---------------- src/moonlight-server/streaming/streaming.hpp | 56 +++++ src/{wolf => moonlight-server}/wolf.cpp | 29 +-- src/streaming/CMakeLists.txt | 65 ------ src/streaming/streaming/streaming.hpp | 38 ---- tests/docker/testDocker.cpp | 2 +- tests/platforms/linux/input.cpp | 6 +- tests/platforms/linux/wayland-display.cpp | 13 +- tests/testGSTPlugin.cpp | 56 ++--- 120 files changed, 635 insertions(+), 608 deletions(-) delete mode 100644 src/audio/CMakeLists.txt create mode 100644 src/core/CMakeLists.txt rename src/{ => core}/rust/gst-plugin-wayland-display/Cargo.toml (100%) rename src/{ => core}/rust/gst-plugin-wayland-display/build.rs (100%) rename src/{ => core}/rust/gst-plugin-wayland-display/src/lib.rs (100%) rename src/{ => core}/rust/gst-plugin-wayland-display/src/utils.rs (100%) rename src/{ => core}/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs (100%) rename src/{ => core}/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/CMakeLists.txt (100%) rename src/{ => core}/rust/gst-wayland-display/Cargo.toml (100%) rename src/{ => core}/rust/gst-wayland-display/include/waylanddisplay.h (100%) rename src/{ => core}/rust/gst-wayland-display/resources/cursor.rgba (100%) rename src/{ => core}/rust/gst-wayland-display/resources/protocols/wayland-drm.xml (100%) rename src/{ => core}/rust/gst-wayland-display/src/comp/focus.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/comp/input.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/comp/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/comp/rendering.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/lib.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/utils/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/utils/target.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/compositor.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/data_device.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/output.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/presentation.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/seat.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/shm.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/handlers/xdg.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/protocols/mod.rs (100%) rename src/{ => core}/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs (100%) create mode 100644 src/core/src/core/api.hpp rename src/{audio/audio => core/src/core}/audio.hpp (97%) rename src/{docker/docker => core/src/core}/docker.hpp (99%) create mode 100644 src/core/src/core/gstreamer.hpp rename src/{input/input => core/src/core}/input.hpp (95%) rename src/{streaming/streaming => core/src/core}/virtual-display.hpp (74%) rename src/{ => core/src/platforms/all}/docker/CMakeLists.txt (93%) rename src/{ => core/src/platforms/all}/docker/docker/docker.cpp (99%) rename src/{ => core/src/platforms/all}/docker/docker/formatters.hpp (97%) rename src/{ => core/src/platforms/all}/docker/docker/json_formatters.hpp (98%) rename src/{ => core/src/platforms/all}/helpers/CMakeLists.txt (100%) rename src/{ => core/src/platforms/all}/helpers/helpers/logger.hpp (100%) rename src/{ => core/src/platforms/all}/helpers/helpers/utils.hpp (100%) create mode 100644 src/core/src/platforms/linux/pulseaudio/CMakeLists.txt rename src/{audio/platforms/linux => core/src/platforms/linux/pulseaudio}/pulse.cpp (98%) create mode 100644 src/core/src/platforms/linux/uinput/CMakeLists.txt rename src/{input/platforms/linux => core/src/platforms/linux/uinput}/keyboard.hpp (99%) rename src/{input/platforms/linux => core/src/platforms/linux/uinput}/uinput.cpp (99%) rename src/{input/platforms/linux => core/src/platforms/linux/uinput}/uinput.hpp (97%) rename src/{streaming/streaming/platforms/linux => core/src/platforms/linux/virtual-display}/wayland-display.cpp (94%) rename src/{audio/platforms/unknown/unknown.cpp => core/src/platforms/unknown/audio.cpp} (92%) rename src/{input => core/src}/platforms/unknown/input.cpp (84%) rename src/{streaming/streaming => core/src}/platforms/unknown/no-virtual-display.cpp (95%) delete mode 100644 src/input/CMakeLists.txt rename src/{moonlight => moonlight-protocol}/CMakeLists.txt (98%) rename src/{ => moonlight-protocol}/crypto/CMakeLists.txt (80%) rename src/{ => moonlight-protocol}/crypto/crypto/crypto.hpp (100%) rename src/{ => moonlight-protocol}/crypto/crypto/utils.hpp (100%) rename src/{ => moonlight-protocol}/crypto/src/aes.hpp (100%) rename src/{ => moonlight-protocol}/crypto/src/crypto.cpp (100%) rename src/{ => moonlight-protocol}/crypto/src/sign.hpp (100%) rename src/{ => moonlight-protocol}/crypto/src/utils.cpp (100%) rename src/{ => moonlight-protocol}/crypto/src/x509.cpp (100%) rename src/{moonlight => moonlight-protocol}/moonlight.cpp (100%) rename src/{moonlight => moonlight-protocol}/moonlight/control.hpp (79%) rename src/{moonlight => moonlight-protocol}/moonlight/data-structures.hpp (100%) rename src/{moonlight => moonlight-protocol}/moonlight/fec.hpp (100%) rename src/{moonlight => moonlight-protocol}/moonlight/protocol.hpp (100%) rename src/{moonlight => moonlight-protocol}/rtsp/parser.hpp (100%) rename src/{wolf => moonlight-server}/CMakeLists.txt (95%) rename src/{wolf => moonlight-server}/control/control.cpp (99%) rename src/{wolf => moonlight-server}/control/control.hpp (100%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/audio.hpp (87%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/gstrtpmoonlightpay_audio.cpp (99%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/gstrtpmoonlightpay_audio.hpp (100%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/gstrtpmoonlightpay_video.cpp (99%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/gstrtpmoonlightpay_video.hpp (100%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/utils.hpp (99%) rename src/{streaming/streaming => moonlight-server}/gst-plugin/video.hpp (91%) rename src/{wolf => moonlight-server}/platforms/hw.hpp (100%) rename src/{wolf => moonlight-server}/platforms/hw_linux.cpp (100%) rename src/{wolf => moonlight-server}/platforms/hw_unknown.cpp (100%) rename src/{wolf => moonlight-server}/rest/custom-https.cpp (100%) rename src/{wolf => moonlight-server}/rest/endpoints.hpp (99%) rename src/{wolf => moonlight-server}/rest/helpers.hpp (100%) rename src/{wolf => moonlight-server}/rest/html/pin.html (100%) rename src/{wolf => moonlight-server}/rest/html/pin.include.html (100%) rename src/{wolf => moonlight-server}/rest/rest.hpp (100%) rename src/{wolf => moonlight-server}/rest/servers.cpp (100%) rename src/{wolf => moonlight-server}/rtp/udp-ping.cpp (100%) rename src/{wolf => moonlight-server}/rtp/udp-ping.hpp (100%) rename src/{wolf => moonlight-server}/rtsp/commands.hpp (96%) rename src/{wolf => moonlight-server}/rtsp/net.hpp (100%) rename src/{wolf => moonlight-server}/runners/docker.hpp (99%) rename src/{wolf => moonlight-server}/runners/process.cpp (100%) rename src/{wolf => moonlight-server}/runners/process.hpp (95%) rename src/{wolf => moonlight-server}/state/config.hpp (100%) rename src/{wolf => moonlight-server}/state/configTOML.cpp (99%) rename src/{wolf => moonlight-server}/state/data-structures.hpp (98%) rename src/{wolf => moonlight-server}/state/default/config.include.toml (100%) rename src/{wolf => moonlight-server}/state/default/config.v2.toml (100%) rename src/{wolf => moonlight-server}/state/sessions.hpp (100%) rename src/{streaming => moonlight-server}/streaming/data-structures.hpp (55%) rename src/{streaming => moonlight-server}/streaming/streaming.cpp (59%) create mode 100644 src/moonlight-server/streaming/streaming.hpp rename src/{wolf => moonlight-server}/wolf.cpp (94%) delete mode 100644 src/streaming/CMakeLists.txt delete mode 100644 src/streaming/streaming/streaming.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aaef8717..8258ea65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,23 +51,11 @@ endif (CCACHE_FOUND) include(FetchContent) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) -option(LINK_RUST_WAYLAND "Link to our custom Rust wayland compositor" ON) -if (LINK_RUST_WAYLAND AND UNIX AND NOT APPLE) - # Adapted from: https://github.com/Devolutions/CMakeRust/ - enable_language(Rust) - include(CMakeCargo) - add_subdirectory(src/rust/gst-wayland-display) -endif () - include(TargetLinkLibrariesSystem) -add_subdirectory(src/helpers) -add_subdirectory(src/crypto) -add_subdirectory(src/moonlight) -add_subdirectory(src/streaming) -add_subdirectory(src/input) -add_subdirectory(src/audio) -add_subdirectory(src/docker) -add_subdirectory(src/wolf) + +add_subdirectory(src/core) +add_subdirectory(src/moonlight-protocol) +add_subdirectory(src/moonlight-server) # Testing only available if this is the main app # Emergency override MODERN_CMAKE_BUILD_TESTING provided as well diff --git a/Cargo.toml b/Cargo.toml index 32a68b00..85e16e24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["src/rust/gst-wayland-display", "src/rust/gst-plugin-wayland-display"] +members = ["src/core/rust/gst-wayland-display", "src/core/rust/gst-plugin-wayland-display"] [workspace.dependencies] gst = { version = "0.20", package = "gstreamer", features = ["v1_18"] } diff --git a/docker/wolf.Dockerfile b/docker/wolf.Dockerfile index 72d58a8b..59922410 100644 --- a/docker/wolf.Dockerfile +++ b/docker/wolf.Dockerfile @@ -44,9 +44,9 @@ RUN --mount=type=cache,target=/cache/ccache \ -DBoost_USE_STATIC_LIBS=ON \ -DBUILD_TESTING=OFF \ -G Ninja && \ - ninja -C $CMAKE_BUILD_DIR && \ + ninja -C $CMAKE_BUILD_DIR wolf && \ # We have to copy out the built executable because this will only be available inside the buildkit cache - cp $CMAKE_BUILD_DIR/src/wolf/wolf /wolf/wolf + cp $CMAKE_BUILD_DIR/src/moonlight-server/wolf /wolf/wolf ######################################################## FROM $BASE_IMAGE AS runner diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt deleted file mode 100644 index 71845f85..00000000 --- a/src/audio/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Make an automatic library - will be static or dynamic based on user setting -add_library(wolf_audio) -add_library(wolf::audio ALIAS wolf_audio) - -target_include_directories(wolf_audio PUBLIC .) -find_package(Boost REQUIRED) -target_link_libraries_system(wolf_audio - PUBLIC - Boost::boost - wolf::helpers) - - -if (UNIX AND NOT APPLE) - find_package(PkgConfig) - find_package(PulseAudio REQUIRED) - if (NOT (PULSEAUDIO_FOUND)) - message(FATAL_ERROR "Please install libpulse: CMake will Exit") - endif () - message(STATUS "Found PulseAudio: ${PULSEAUDIO_VERSION}") - target_link_libraries(wolf_audio PUBLIC pulse) - target_include_directories(wolf_audio PUBLIC ${PULSEAUDIO_INCLUDE_DIR}) - target_sources(wolf_audio - PUBLIC audio/audio.hpp platforms/linux/pulse.cpp) -else () - message(WARNING "Missing audio control for the current platform") - target_sources(wolf_audio - PUBLIC audio/audio.hpp - PRIVATE platforms/unknown/unknown.cpp) -endif () - -# All users of this library will need at least C++17 -target_compile_features(wolf_audio PUBLIC cxx_std_17) \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 00000000..40d53846 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,72 @@ +add_library(wolf_core) +add_library(wolf::core ALIAS wolf_core) + +target_include_directories(wolf_core PUBLIC src) + +# Platform agnostic code +add_subdirectory(src/platforms/all/helpers) +target_link_libraries(wolf_core PUBLIC wolf::helpers) + +add_subdirectory(src/platforms/all/docker) +target_link_libraries(wolf_core PUBLIC wolf::docker) + +file(GLOB CORE_HEADERS CONFIGURE_DEPENDS src/core/*.hpp) +set(CORE_SRC "") + +option(LINK_RUST_WAYLAND "Link to our custom Rust wayland compositor" ON) +if (LINK_RUST_WAYLAND AND UNIX AND NOT APPLE) + # Adapted from: https://github.com/Devolutions/CMakeRust/ + enable_language(Rust) + include(CMakeCargo) + add_subdirectory(rust/gst-wayland-display) +endif () + +FetchContent_Declare( + immer + GIT_REPOSITORY https://github.com/arximboldi/immer.git + GIT_TAG e02cbd795e9424a8405a8cb01f659ad61c0cbbc7) +set(immer_BUILD_TESTS OFF) +set(immer_BUILD_EXAMPLES OFF) +set(immer_BUILD_DOCS OFF) +set(immer_BUILD_EXTRAS OFF) + +set(FPHSA_NAME_MISMATCHED on) # see: https://github.com/arximboldi/immer/issues/204 +FetchContent_MakeAvailable(immer) +target_link_libraries_system(wolf_core PUBLIC immer) +unset(FPHSA_NAME_MISMATCHED) + +find_package(PkgConfig) +pkg_check_modules(GSTREAMER REQUIRED IMPORTED_TARGET gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0) +pkg_check_modules(GLIB2 REQUIRED IMPORTED_TARGET glib-2.0) + +if (NOT (GSTREAMER_FOUND)) + message(FATAL_ERROR "Please Install Gstreamer Dev: CMake will Exit") +endif () +target_link_libraries(wolf_core PUBLIC + PkgConfig::GSTREAMER + PkgConfig::GLIB2) + +# Platform dependent code +if (UNIX AND NOT APPLE) + add_subdirectory(src/platforms/linux/pulseaudio) + target_link_libraries(wolf_core PUBLIC wolf::audio) + + add_subdirectory(src/platforms/linux/uinput) + target_link_libraries(wolf_core PUBLIC wolf::uinput) + + if (LINK_RUST_WAYLAND) + target_link_libraries_system(wolf_core PUBLIC gstwaylanddisplay) + list(APPEND CORE_SRC src/platforms/linux/virtual-display/wayland-display.cpp) + else () + message(WARNING "Missing virtual display implementation for this platform") + list(APPEND CORE_SRC platforms/unknown/no-virtual-display.cpp) + endif () +else () + file(GLOB CORE_SRC SRCS platforms/unknown/*.cpp) +endif () + +target_sources(wolf_core PUBLIC ${CORE_HEADERS} PRIVATE ${CORE_SRC}) + +# All users of this library will need at least C++17 +target_compile_features(wolf_core PUBLIC cxx_std_17) +set_target_properties(wolf_core PROPERTIES LINKER_LANGUAGE CXX) diff --git a/src/rust/gst-plugin-wayland-display/Cargo.toml b/src/core/rust/gst-plugin-wayland-display/Cargo.toml similarity index 100% rename from src/rust/gst-plugin-wayland-display/Cargo.toml rename to src/core/rust/gst-plugin-wayland-display/Cargo.toml diff --git a/src/rust/gst-plugin-wayland-display/build.rs b/src/core/rust/gst-plugin-wayland-display/build.rs similarity index 100% rename from src/rust/gst-plugin-wayland-display/build.rs rename to src/core/rust/gst-plugin-wayland-display/build.rs diff --git a/src/rust/gst-plugin-wayland-display/src/lib.rs b/src/core/rust/gst-plugin-wayland-display/src/lib.rs similarity index 100% rename from src/rust/gst-plugin-wayland-display/src/lib.rs rename to src/core/rust/gst-plugin-wayland-display/src/lib.rs diff --git a/src/rust/gst-plugin-wayland-display/src/utils.rs b/src/core/rust/gst-plugin-wayland-display/src/utils.rs similarity index 100% rename from src/rust/gst-plugin-wayland-display/src/utils.rs rename to src/core/rust/gst-plugin-wayland-display/src/utils.rs diff --git a/src/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs b/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs similarity index 100% rename from src/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs rename to src/core/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs diff --git a/src/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs b/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs similarity index 100% rename from src/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs rename to src/core/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs diff --git a/src/rust/gst-wayland-display/CMakeLists.txt b/src/core/rust/gst-wayland-display/CMakeLists.txt similarity index 100% rename from src/rust/gst-wayland-display/CMakeLists.txt rename to src/core/rust/gst-wayland-display/CMakeLists.txt diff --git a/src/rust/gst-wayland-display/Cargo.toml b/src/core/rust/gst-wayland-display/Cargo.toml similarity index 100% rename from src/rust/gst-wayland-display/Cargo.toml rename to src/core/rust/gst-wayland-display/Cargo.toml diff --git a/src/rust/gst-wayland-display/include/waylanddisplay.h b/src/core/rust/gst-wayland-display/include/waylanddisplay.h similarity index 100% rename from src/rust/gst-wayland-display/include/waylanddisplay.h rename to src/core/rust/gst-wayland-display/include/waylanddisplay.h diff --git a/src/rust/gst-wayland-display/resources/cursor.rgba b/src/core/rust/gst-wayland-display/resources/cursor.rgba similarity index 100% rename from src/rust/gst-wayland-display/resources/cursor.rgba rename to src/core/rust/gst-wayland-display/resources/cursor.rgba diff --git a/src/rust/gst-wayland-display/resources/protocols/wayland-drm.xml b/src/core/rust/gst-wayland-display/resources/protocols/wayland-drm.xml similarity index 100% rename from src/rust/gst-wayland-display/resources/protocols/wayland-drm.xml rename to src/core/rust/gst-wayland-display/resources/protocols/wayland-drm.xml diff --git a/src/rust/gst-wayland-display/src/comp/focus.rs b/src/core/rust/gst-wayland-display/src/comp/focus.rs similarity index 100% rename from src/rust/gst-wayland-display/src/comp/focus.rs rename to src/core/rust/gst-wayland-display/src/comp/focus.rs diff --git a/src/rust/gst-wayland-display/src/comp/input.rs b/src/core/rust/gst-wayland-display/src/comp/input.rs similarity index 100% rename from src/rust/gst-wayland-display/src/comp/input.rs rename to src/core/rust/gst-wayland-display/src/comp/input.rs diff --git a/src/rust/gst-wayland-display/src/comp/mod.rs b/src/core/rust/gst-wayland-display/src/comp/mod.rs similarity index 100% rename from src/rust/gst-wayland-display/src/comp/mod.rs rename to src/core/rust/gst-wayland-display/src/comp/mod.rs diff --git a/src/rust/gst-wayland-display/src/comp/rendering.rs b/src/core/rust/gst-wayland-display/src/comp/rendering.rs similarity index 100% rename from src/rust/gst-wayland-display/src/comp/rendering.rs rename to src/core/rust/gst-wayland-display/src/comp/rendering.rs diff --git a/src/rust/gst-wayland-display/src/lib.rs b/src/core/rust/gst-wayland-display/src/lib.rs similarity index 100% rename from src/rust/gst-wayland-display/src/lib.rs rename to src/core/rust/gst-wayland-display/src/lib.rs diff --git a/src/rust/gst-wayland-display/src/utils/mod.rs b/src/core/rust/gst-wayland-display/src/utils/mod.rs similarity index 100% rename from src/rust/gst-wayland-display/src/utils/mod.rs rename to src/core/rust/gst-wayland-display/src/utils/mod.rs diff --git a/src/rust/gst-wayland-display/src/utils/target.rs b/src/core/rust/gst-wayland-display/src/utils/target.rs similarity index 100% rename from src/rust/gst-wayland-display/src/utils/target.rs rename to src/core/rust/gst-wayland-display/src/utils/target.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/compositor.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/compositor.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/compositor.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/compositor.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/data_device.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/data_device.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/data_device.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/data_device.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/mod.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/mod.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/mod.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/output.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/output.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/output.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/output.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/presentation.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/presentation.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/presentation.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/presentation.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/seat.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/seat.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/seat.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/seat.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/shm.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/shm.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/shm.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/shm.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs diff --git a/src/rust/gst-wayland-display/src/wayland/handlers/xdg.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/xdg.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/handlers/xdg.rs rename to src/core/rust/gst-wayland-display/src/wayland/handlers/xdg.rs diff --git a/src/rust/gst-wayland-display/src/wayland/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/mod.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/mod.rs rename to src/core/rust/gst-wayland-display/src/wayland/mod.rs diff --git a/src/rust/gst-wayland-display/src/wayland/protocols/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/protocols/mod.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/protocols/mod.rs rename to src/core/rust/gst-wayland-display/src/wayland/protocols/mod.rs diff --git a/src/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs b/src/core/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs similarity index 100% rename from src/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs rename to src/core/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs diff --git a/src/core/src/core/api.hpp b/src/core/src/core/api.hpp new file mode 100644 index 00000000..42fdc478 --- /dev/null +++ b/src/core/src/core/api.hpp @@ -0,0 +1,51 @@ +#pragma once +#include +#include +#include + +namespace wolf::core::api { + +enum PACKET_TYPE : std::uint16_t { + START_A = boost::endian::little_to_native(0x0305), + START_B = boost::endian::little_to_native(0x0307), + INVALIDATE_REF_FRAMES = boost::endian::little_to_native(0x0301), + LOSS_STATS = boost::endian::little_to_native(0x0201), + FRAME_STATS = boost::endian::little_to_native(0x0204), + INPUT_DATA = boost::endian::little_to_native(0x0206), + RUMBLE_DATA = boost::endian::little_to_native(0x010b), + TERMINATION = boost::endian::little_to_native(0x0109), + PERIODIC_PING = boost::endian::little_to_native(0x0200), + IDR_FRAME = boost::endian::little_to_native(0x0302), + ENCRYPTED = boost::endian::little_to_native(0x0001) +}; + +/** + * Events received in the ControlSession will be fired up in the event_bus + */ +struct ControlEvent { + // A unique ID that identifies this session + std::size_t session_id; + + PACKET_TYPE type; + std::string_view raw_packet; +}; + +struct PauseStreamEvent { + std::size_t session_id; +}; + +struct ResumeStreamEvent { + std::size_t session_id; +}; + +struct StopStreamEvent { + std::size_t session_id; +}; + +struct DisplayMode { + int width; + int height; + int refreshRate; +}; + +} // namespace wolf::core::api \ No newline at end of file diff --git a/src/audio/audio/audio.hpp b/src/core/src/core/audio.hpp similarity index 97% rename from src/audio/audio/audio.hpp rename to src/core/src/core/audio.hpp index 04cca548..cfe6d749 100644 --- a/src/audio/audio/audio.hpp +++ b/src/core/src/core/audio.hpp @@ -9,7 +9,7 @@ #include #include -namespace audio { +namespace wolf::core::audio { typedef struct Server Server; diff --git a/src/docker/docker/docker.hpp b/src/core/src/core/docker.hpp similarity index 99% rename from src/docker/docker/docker.hpp rename to src/core/src/core/docker.hpp index 72ff08ef..56a947a1 100644 --- a/src/docker/docker/docker.hpp +++ b/src/core/src/core/docker.hpp @@ -5,7 +5,7 @@ #include #include -namespace docker { +namespace wolf::core::docker { constexpr auto DOCKER_API_VERSION = "v1.40"; enum ContainerStatus { diff --git a/src/core/src/core/gstreamer.hpp b/src/core/src/core/gstreamer.hpp new file mode 100644 index 00000000..e1adf402 --- /dev/null +++ b/src/core/src/core/gstreamer.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace wolf::core::gstreamer { + +using namespace wolf::core::api; + +using gst_element_ptr = std::shared_ptr; +using gst_main_loop_ptr = std::shared_ptr; + +static void pipeline_error_handler(GstBus *bus, GstMessage *message, gpointer data) { + auto loop = (GMainLoop *)data; + GError *err; + gchar *debug; + gst_message_parse_error(message, &err, &debug); + logs::log(logs::error, "[GSTREAMER] Pipeline error: {}", err->message); + g_error_free(err); + g_free(debug); + + /* Terminate pipeline on error */ + g_main_loop_quit(loop); +} + +static void pipeline_eos_handler(GstBus *bus, GstMessage *message, gpointer data) { + auto loop = (GMainLoop *)data; + logs::log(logs::info, "[GSTREAMER] Pipeline reached End Of Stream"); + g_main_loop_quit(loop); +} + +static bool +run_pipeline(const std::string &pipeline_desc, + std::size_t session_id, + const std::shared_ptr &event_bus, + const std::function>(GstElement *)> &on_pipeline_ready) { + GError *error = nullptr; + gst_element_ptr pipeline(gst_parse_launch(pipeline_desc.c_str(), &error), [session_id](const auto &pipeline) { + logs::log(logs::trace, "~pipeline {}", session_id); + gst_object_unref(pipeline); + }); + + if (!pipeline) { + logs::log(logs::error, "[GSTREAMER] Pipeline parse error: {}", error->message); + g_error_free(error); + return false; + } else if (error) { // Please note that you might get a return value that is not NULL even though the error is set. In + // this case there was a recoverable parsing error and you can try to play the pipeline. + logs::log(logs::warning, "[GSTREAMER] Pipeline parse error (recovered): {}", error->message); + g_error_free(error); + } + + /* + * create a mainloop that runs/iterates the default GLib main context + * (context NULL), in other words: makes the context check if anything + * it watches for has happened. When a message has been posted on the + * bus, the default main context will automatically call our + * my_bus_callback() function to notify us of that message. + */ + gst_main_loop_ptr loop(g_main_loop_new(nullptr, FALSE), ::g_main_loop_unref); + + /* + * adds a watch for new message on our pipeline's message bus to + * the default GLib main context, which is the main context that our + * GLib main loop is attached to below + */ + auto bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline.get())); + gst_bus_add_signal_watch(bus); + g_signal_connect(bus, "message::error", G_CALLBACK(pipeline_error_handler), loop.get()); + g_signal_connect(bus, "message::eos", G_CALLBACK(pipeline_eos_handler), loop.get()); + gst_object_unref(bus); + + /* Set the pipeline to "playing" state*/ + gst_element_set_state(pipeline.get(), GST_STATE_PLAYING); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(reinterpret_cast(pipeline.get()), + GST_DEBUG_GRAPH_SHOW_ALL, + "pipeline-start"); + + /* Let the calling thread set extra things */ + auto handlers = on_pipeline_ready(pipeline.get()); + + auto pause_handler = event_bus->register_handler>( + [session_id, loop](const immer::box &ev) { + if (ev->session_id == session_id) { + logs::log(logs::debug, "[GSTREAMER] Pausing pipeline: {}", session_id); + + /** + * Unfortunately here we can't just pause the pipeline, + * when a pipeline will be resumed there are a lot of breaking changes like: + * - Client IP:PORT + * - AES key and IV for encrypted payloads + * - Client resolution, framerate, and encoding + * + * The only solution is to kill the pipeline and re-create it again when a resume happens + */ + + g_main_loop_quit(loop.get()); + } + }); + + auto stop_handler = event_bus->register_handler>( + [session_id, loop](const immer::box &ev) { + if (ev->session_id == session_id) { + logs::log(logs::debug, "[GSTREAMER] Stopping pipeline: {}", session_id); + g_main_loop_quit(loop.get()); + } + }); + + /* The main loop will be run until someone calls g_main_loop_quit() */ + g_main_loop_run(loop.get()); + + logs::log(logs::debug, "[GSTREAMER] Ending pipeline: {}", session_id); + + /* Out of the main loop, clean up nicely */ + gst_element_set_state(pipeline.get(), GST_STATE_PAUSED); + gst_element_set_state(pipeline.get(), GST_STATE_READY); + gst_element_set_state(pipeline.get(), GST_STATE_NULL); + + for (const auto &handler : handlers) { + handler->unregister(); + } + pause_handler.unregister(); + stop_handler.unregister(); + + return true; +} + +/** + * Sends a custom message in the pipeline + */ +static void send_message(GstElement *recipient, GstStructure *message) { + auto gst_ev = gst_event_new_custom(GST_EVENT_CUSTOM_UPSTREAM, message); + gst_element_send_event(recipient, gst_ev); +} +} // namespace wolf::core::gstreamer \ No newline at end of file diff --git a/src/input/input/input.hpp b/src/core/src/core/input.hpp similarity index 95% rename from src/input/input/input.hpp rename to src/core/src/core/input.hpp index 53630fed..5b511412 100644 --- a/src/input/input/input.hpp +++ b/src/core/src/core/input.hpp @@ -1,17 +1,14 @@ #pragma once -#include "moonlight/control.hpp" -#include "moonlight/data-structures.hpp" #include -#include +#include #include #include #include #include -#include #include -namespace input { +namespace wolf::core::input { struct InputReady { immer::array devices_paths; diff --git a/src/streaming/streaming/virtual-display.hpp b/src/core/src/core/virtual-display.hpp similarity index 74% rename from src/streaming/streaming/virtual-display.hpp rename to src/core/src/core/virtual-display.hpp index a6128065..f8a46044 100644 --- a/src/streaming/streaming/virtual-display.hpp +++ b/src/core/src/core/virtual-display.hpp @@ -1,33 +1,28 @@ #pragma once +#include +#include #include #include #include -#include +#include -namespace streaming { +namespace wolf::core::virtual_display { typedef struct WaylandState WaylandState; -static void destroy(WaylandState *w_state); using wl_state_ptr = std::shared_ptr; - -struct GstAppDataState { - gst_element_ptr app_src; - wl_state_ptr wayland_state; - guint source_id{}; - int framerate; - GstClockTime timestamp = 0; -}; +using gst_element_ptr = std::shared_ptr; wl_state_ptr create_wayland_display(const immer::array &input_devices, const std::string &render_node = "/dev/dri/renderD128"); std::unique_ptr set_resolution(WaylandState &w_state, - const moonlight::DisplayMode &display_mode, + const wolf::core::api::DisplayMode &display_mode, const std::optional &app_src = {}); immer::vector get_devices(const WaylandState &w_state); immer::vector get_env(const WaylandState &w_state); +static void destroy(WaylandState *w_state); GstBuffer *get_frame(WaylandState &w_state); -} // namespace streaming \ No newline at end of file +} // namespace wolf::core::virtual_display \ No newline at end of file diff --git a/src/docker/CMakeLists.txt b/src/core/src/platforms/all/docker/CMakeLists.txt similarity index 93% rename from src/docker/CMakeLists.txt rename to src/core/src/platforms/all/docker/CMakeLists.txt index 522d61f2..51fe35f4 100644 --- a/src/docker/CMakeLists.txt +++ b/src/core/src/platforms/all/docker/CMakeLists.txt @@ -2,10 +2,9 @@ add_library(wolf_docker) add_library(wolf::docker ALIAS wolf_docker) -target_include_directories(wolf_docker PUBLIC .) +target_include_directories(wolf_docker PUBLIC . PRIVATE ../../../) target_sources(wolf_docker PUBLIC - docker/docker.hpp docker/formatters.hpp PRIVATE diff --git a/src/docker/docker/docker.cpp b/src/core/src/platforms/all/docker/docker/docker.cpp similarity index 99% rename from src/docker/docker/docker.cpp rename to src/core/src/platforms/all/docker/docker/docker.cpp index 32df9a2f..43474368 100644 --- a/src/docker/docker/docker.cpp +++ b/src/core/src/platforms/all/docker/docker/docker.cpp @@ -1,13 +1,13 @@ #include #include -#include +#include #include #include #include #include #include -namespace docker { +namespace wolf::core::docker { using namespace ranges; namespace json = boost::json; diff --git a/src/docker/docker/formatters.hpp b/src/core/src/platforms/all/docker/docker/formatters.hpp similarity index 97% rename from src/docker/docker/formatters.hpp rename to src/core/src/platforms/all/docker/docker/formatters.hpp index f1200775..b34d01d3 100644 --- a/src/docker/docker/formatters.hpp +++ b/src/core/src/platforms/all/docker/docker/formatters.hpp @@ -1,9 +1,11 @@ #pragma once -#include +#include #include #include +using namespace wolf::core; + namespace fmt { template <> struct [[maybe_unused]] formatter { diff --git a/src/docker/docker/json_formatters.hpp b/src/core/src/platforms/all/docker/docker/json_formatters.hpp similarity index 98% rename from src/docker/docker/json_formatters.hpp rename to src/core/src/platforms/all/docker/docker/json_formatters.hpp index f3bc6785..c8704cb5 100644 --- a/src/docker/docker/json_formatters.hpp +++ b/src/core/src/platforms/all/docker/docker/json_formatters.hpp @@ -1,9 +1,11 @@ #pragma once #include -#include +#include #include #include +using namespace wolf::core; + namespace boost::json { void tag_invoke(value_from_tag, value &jv, const std::vector &ports) { diff --git a/src/helpers/CMakeLists.txt b/src/core/src/platforms/all/helpers/CMakeLists.txt similarity index 100% rename from src/helpers/CMakeLists.txt rename to src/core/src/platforms/all/helpers/CMakeLists.txt diff --git a/src/helpers/helpers/logger.hpp b/src/core/src/platforms/all/helpers/helpers/logger.hpp similarity index 100% rename from src/helpers/helpers/logger.hpp rename to src/core/src/platforms/all/helpers/helpers/logger.hpp diff --git a/src/helpers/helpers/utils.hpp b/src/core/src/platforms/all/helpers/helpers/utils.hpp similarity index 100% rename from src/helpers/helpers/utils.hpp rename to src/core/src/platforms/all/helpers/helpers/utils.hpp diff --git a/src/core/src/platforms/linux/pulseaudio/CMakeLists.txt b/src/core/src/platforms/linux/pulseaudio/CMakeLists.txt new file mode 100644 index 00000000..b061b4b8 --- /dev/null +++ b/src/core/src/platforms/linux/pulseaudio/CMakeLists.txt @@ -0,0 +1,24 @@ +# Make an automatic library - will be static or dynamic based on user setting +add_library(wolf_audio) +add_library(wolf::audio ALIAS wolf_audio) + +target_include_directories(wolf_audio PRIVATE ../../../) +find_package(Boost REQUIRED) +target_link_libraries_system(wolf_audio + PUBLIC + Boost::boost + wolf::helpers) + + +find_package(PkgConfig) +find_package(PulseAudio REQUIRED) +if (NOT (PULSEAUDIO_FOUND)) + message(FATAL_ERROR "Please install libpulse: CMake will Exit") +endif () +message(STATUS "Found PulseAudio: ${PULSEAUDIO_VERSION}") +target_link_libraries(wolf_audio PUBLIC pulse) +target_include_directories(wolf_audio PUBLIC ${PULSEAUDIO_INCLUDE_DIR}) +target_sources(wolf_audio PUBLIC pulse.cpp) + +# All users of this library will need at least C++17 +target_compile_features(wolf_audio PUBLIC cxx_std_17) \ No newline at end of file diff --git a/src/audio/platforms/linux/pulse.cpp b/src/core/src/platforms/linux/pulseaudio/pulse.cpp similarity index 98% rename from src/audio/platforms/linux/pulse.cpp rename to src/core/src/platforms/linux/pulseaudio/pulse.cpp index 2b6c0763..8a8d3f59 100644 --- a/src/audio/platforms/linux/pulse.cpp +++ b/src/core/src/platforms/linux/pulseaudio/pulse.cpp @@ -1,9 +1,9 @@ -#include