diff --git a/.gitattributes b/.gitattributes index 3e0ae29c..a1b22303 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,5 @@ -# ensure dockerfiles are checked out with LF line endings +# ensure Linux specific files are checked out with LF line endings Dockerfile text eol=lf *.dockerfile text eol=lf - -# ensure flatpak lint json files are checked out with LF line endings *flatpak-lint-*.json text eol=lf +*.sh text eol=lf diff --git a/.github/matchers/copr-ci.json b/.github/matchers/copr-ci.json new file mode 100644 index 00000000..d884c61a --- /dev/null +++ b/.github/matchers/copr-ci.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "copr-ci-gcc", + "pattern": [ + { + "regexp": "^/?(?:[^/]+/){5}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] +} diff --git a/.github/matchers/docker.json b/.github/matchers/docker.json new file mode 100644 index 00000000..df43ee03 --- /dev/null +++ b/.github/matchers/docker.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "docker-gcc", + "pattern": [ + { + "regexp": "^(?:#\\d+\\s+\\d+\\.\\d+\\s+)?/?(?:[^/]+/){2}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] +} diff --git a/.github/matchers/gcc-strip3.json b/.github/matchers/gcc-strip3.json new file mode 100644 index 00000000..8b6027f2 --- /dev/null +++ b/.github/matchers/gcc-strip3.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "gcc-strip3", + "pattern": [ + { + "regexp": "^/?(?:[^/]+/){3}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] +} diff --git a/.github/matchers/gcc.json b/.github/matchers/gcc.json new file mode 100644 index 00000000..13f987bf --- /dev/null +++ b/.github/matchers/gcc.json @@ -0,0 +1,29 @@ +{ + "problemMatcher": [ + { + "owner": "gcc", + "pattern": [ + { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + }, + { + "owner": "doxygen", + "pattern": [ + { + "regexp": "^.*?([A-Za-z]:[\\\\/][^:]+|[\\\\/][^:]+):(\\d+): ([a-zA-Z]+): (.+)$", + "file": 1, + "line": 2, + "severity": 3, + "message": 4 + } + ] + } + ] +} diff --git a/cmake/packaging/linux.cmake b/cmake/packaging/linux.cmake index 041430dc..24d084a7 100644 --- a/cmake/packaging/linux.cmake +++ b/cmake/packaging/linux.cmake @@ -45,6 +45,7 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ libcap2, \ libcurl4, \ libdrm2, \ + libgbm1, \ libevdev2, \ libnuma1, \ libopus0, \ @@ -65,6 +66,7 @@ set(CPACK_RPM_PACKAGE_REQUIRES "\ libva >= 2.14.0, \ libwayland-client >= 1.20.0, \ libX11 >= 1.7.3.1, \ + mesa-libgbm >= 25.0.7, \ miniupnpc >= 2.2.4, \ numactl-libs >= 2.0.14, \ openssl >= 3.0.2, \ diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake index 67c767b2..5170111d 100644 --- a/cmake/packaging/windows.cmake +++ b/cmake/packaging/windows.cmake @@ -4,6 +4,20 @@ install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application) # Hardening: include zlib1.dll (loaded via LoadLibrary() in openssl's libcrypto.a) install(FILES "${ZLIB}" DESTINATION "." COMPONENT application) +# ViGEmBus installer +set(VIGEMBUS_INSTALLER "${CMAKE_BINARY_DIR}/vigembus_installer.exe") +file(DOWNLOAD + "https://github.com/nefarius/ViGEmBus/releases/download/v1.21.442.0/ViGEmBus_1.21.442_x64_x86_arm64.exe" + ${VIGEMBUS_INSTALLER} + SHOW_PROGRESS + EXPECTED_HASH SHA256=155c50f1eec07bdc28d2f61a3e3c2c6c132fee7328412de224695f89143316bc + TIMEOUT 60 +) +install(FILES ${VIGEMBUS_INSTALLER} + DESTINATION "scripts" + RENAME "vigembus_installer.exe" + COMPONENT gamepad) + # Adding tools install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi) install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio) diff --git a/cmake/packaging/windows_nsis.cmake b/cmake/packaging/windows_nsis.cmake index 79454b7c..50e43749 100644 --- a/cmake/packaging/windows_nsis.cmake +++ b/cmake/packaging/windows_nsis.cmake @@ -16,7 +16,8 @@ SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS nsExec::ExecToLog '\\\"$INSTDIR\\\\drivers\\\\sudovda\\\\install.bat\\\"' nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"' nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"' - nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-gamepad.bat\\\"' + nsExec::ExecToLog \ + 'powershell.exe -ExecutionPolicy Bypass -File \\\"$INSTDIR\\\\scripts\\\\install-gamepad.ps1\\\"' nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"' nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\autostart-service.bat\\\"' NoController: @@ -32,7 +33,9 @@ set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS MessageBox MB_YESNO|MB_ICONQUESTION \ 'Do you want to remove Virtual Gamepad?' \ /SD IDNO IDNO NoGamepad - nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.bat\\\"'; skipped if no + nsExec::ExecToLog \ + 'powershell.exe -ExecutionPolicy Bypass -File \\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.ps1\\\"'; \ + skipped if no NoGamepad: MessageBox MB_YESNO|MB_ICONQUESTION \ 'Do you want to remove SudoVDA Virtual Display Driver?' \ diff --git a/cmake/prep/build_version.cmake b/cmake/prep/build_version.cmake index 69c4d7cd..3043c86f 100644 --- a/cmake/prep/build_version.cmake +++ b/cmake/prep/build_version.cmake @@ -1,18 +1,18 @@ # Set build variables if env variables are defined # These are used in configured files such as manifests for different packages -if(DEFINED ENV{BRANCH}) # cmake-lint: disable=W0106 +if(DEFINED ENV{BRANCH}) set(GITHUB_BRANCH $ENV{BRANCH}) endif() if(DEFINED ENV{BUILD_VERSION}) # cmake-lint: disable=W0106 set(BUILD_VERSION $ENV{BUILD_VERSION}) endif() -if(DEFINED ENV{CLONE_URL}) # cmake-lint: disable=W0106 +if(DEFINED ENV{CLONE_URL}) set(GITHUB_CLONE_URL $ENV{CLONE_URL}) endif() -if(DEFINED ENV{COMMIT}) # cmake-lint: disable=W0106 +if(DEFINED ENV{COMMIT}) set(GITHUB_COMMIT $ENV{COMMIT}) endif() -if(DEFINED ENV{TAG}) # cmake-lint: disable=W0106 +if(DEFINED ENV{TAG}) set(GITHUB_TAG $ENV{TAG}) endif() diff --git a/cmake/targets/common.cmake b/cmake/targets/common.cmake index 4cff2ce6..ba378cbb 100644 --- a/cmake/targets/common.cmake +++ b/cmake/targets/common.cmake @@ -27,7 +27,7 @@ endif() target_link_libraries(sunshine ${SUNSHINE_EXTERNAL_LIBRARIES} ${EXTRA_LIBS}) target_compile_definitions(sunshine PUBLIC ${SUNSHINE_DEFINITIONS}) -set_target_properties(sunshine PROPERTIES CXX_STANDARD 20 +set_target_properties(sunshine PROPERTIES CXX_STANDARD 23 VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) diff --git a/docker/archlinux.dockerfile b/docker/archlinux.dockerfile index 89071f60..63a9be63 100644 --- a/docker/archlinux.dockerfile +++ b/docker/archlinux.dockerfile @@ -32,7 +32,6 @@ ENV CLONE_URL=${CLONE_URL} SHELL ["/bin/bash", "-o", "pipefail", "-c"] -# hadolint ignore=SC2016 RUN <<_SETUP #!/bin/bash set -e @@ -42,6 +41,7 @@ useradd -m builder echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers # patch the build flags +# shellcheck disable=SC2016 sed -i 's,#MAKEFLAGS="-j2",MAKEFLAGS="-j$(nproc)",g' /etc/makepkg.conf # install dependencies diff --git a/docker/clion-toolchain.dockerfile b/docker/clion-toolchain.dockerfile index ec54568c..f5080d18 100644 --- a/docker/clion-toolchain.dockerfile +++ b/docker/clion-toolchain.dockerfile @@ -19,7 +19,6 @@ ENV DISPLAY=:0 SHELL ["/bin/bash", "-o", "pipefail", "-c"] # install dependencies -# hadolint ignore=SC1091 RUN <<_DEPS #!/bin/bash set -e @@ -74,7 +73,6 @@ WORKDIR /build/cuda # versions: https://developer.nvidia.com/cuda-toolkit-archive ENV CUDA_VERSION="11.8.0" ENV CUDA_BUILD="520.61.05" -# hadolint ignore=SC3010 RUN <<_INSTALL_CUDA #!/bin/bash set -e diff --git a/docker/debian-bookworm.dockerfile b/docker/debian-bookworm.dockerfile index f88cea05..ffa68b7c 100644 --- a/docker/debian-bookworm.dockerfile +++ b/docker/debian-bookworm.dockerfile @@ -42,7 +42,6 @@ _BUILD # run tests WORKDIR /build/sunshine/build/tests -# hadolint ignore=SC1091 RUN <<_TEST #!/bin/bash set -e diff --git a/docker/ubuntu-22.04.dockerfile b/docker/ubuntu-22.04.dockerfile index 7bb24eb8..06032175 100644 --- a/docker/ubuntu-22.04.dockerfile +++ b/docker/ubuntu-22.04.dockerfile @@ -42,7 +42,6 @@ _BUILD # run tests WORKDIR /build/sunshine/build/tests -# hadolint ignore=SC1091 RUN <<_TEST #!/bin/bash set -e diff --git a/docker/ubuntu-24.04.dockerfile b/docker/ubuntu-24.04.dockerfile index 984cfdcb..e11f18b2 100644 --- a/docker/ubuntu-24.04.dockerfile +++ b/docker/ubuntu-24.04.dockerfile @@ -42,7 +42,6 @@ _BUILD # run tests WORKDIR /build/sunshine/build/tests -# hadolint ignore=SC1091 RUN <<_TEST #!/bin/bash set -e diff --git a/docs/configuration.md b/docs/configuration.md index 0d860111..b37578e2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1291,7 +1291,7 @@ editing the `conf` file in a text editor. Use the examples as reference. Remap the requested resolution and FPS to another display mode.
Depending on the [dd_resolution_option](#dd_resolution_option) and - [dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping + [dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping groups are available: - For each of those groups, a list of fields can be configured to perform remapping: + For each of those groups, a list of fields can be configured to perform remapping: If `requested_*` field is left empty, it will match everything.
- If `final_*` field is left empty, the original value will not be remapped and either a requested, manual - or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered + If `final_*` field is left empty, the original value will not be remapped and either a requested, manual + or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered invalid.
- @note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution` + @note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution` field to be considered.} @note{First entry to be matched in the list is the one that will be used.} @tip{`requested_resolution` and `final_resolution` can be omitted for `refresh_rate_only` group.} @@ -1392,6 +1392,32 @@ editing the `conf` file in a text editor. Use the examples as reference. +### minimum_fps_target + + + + + + + + + + + + + + + + + + + +
Description + Sunshine tries to save bandwidth when content on screen is static or a low framerate. Because many clients expect a constant stream of video frames, a certain amount of duplicate frames are sent when this happens. This setting controls the lowest effective framerate a stream can reach. +
Default@code{} + 0 + @endcode
Choices0Use half the stream's FPS as the minimum target.
1-1000Specify your own value. The real minimum may differ from this value.
+ ## Network ### upnp diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 8bd22eed..479956bb 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -84,9 +84,35 @@ client only 1 Gbit/s or Wi-Fi. Similarly, a 1 Gbps host may be too fast for a client having only a 100 Mbps interface. As a workaround the transmission speed of the host NIC can be reduced: 1 Gbps -instead of 2.5 or 100 Mbps instead of 1 Gbps. (A technically more advanced +instead of 2.5 or 100 Mbps instead of 1 Gbps. A technically more advanced solution would be to configure traffic shaping rules at the OS-level, so that -only Sunshine's traffic is slowed down.) +only Sunshine's traffic is slowed down. + +Such a solution on Linux could look like that: + +```bash +# 1) Remove existing qdisc (pfifo_fast) +sudo tc qdisc del dev root + +# 2) Add HTB root qdisc with default class 1:1 +sudo tc qdisc add dev root handle 1: htb default 1 + +# 3) Create class 1:1 for full 10 Gbit/s (all other traffic) +sudo tc class add dev parent 1: classid 1:1 htb \ + rate 10000mbit ceil 10000mbit burst 32k + +# 4) Create class 1:10 for Sunshine game stream at 1 Gbit/s +sudo tc class add dev parent 1: classid 1:10 htb \ + rate 1000mbit ceil 1000mbit burst 32k + +# 5) Filter UDP source port 47998 into class 1:10 +sudo tc filter add dev protocol ip parent 1: prio 1 \ + u32 match ip protocol 17 0xff \ + match ip sport 47998 0xffff flowid 1:10 +``` + +In that way only the Sunshine traffic is limited by 1 Gbit. This is not persistent on reboots. +If you use a different port for the game stream you need to adjust the last command. Sunshine versions > 0.23.1 include improved networking code that should alleviate or even solve this issue (without reducing the NIC speed). diff --git a/package.json b/package.json index 0e7c10d4..39094545 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "@lizardbyte/shared-web": "2025.626.181239", - "vue": "3.5.17", - "vue-i18n": "11.1.9" + "vue": "3.5.18", + "vue-i18n": "11.1.11" }, "devDependencies": { "@codecov/vite-plugin": "1.9.1", diff --git a/packaging/linux/fedora/Sunshine.spec b/packaging/linux/fedora/Sunshine.spec index d98bbbf1..d027b361 100644 --- a/packaging/linux/fedora/Sunshine.spec +++ b/packaging/linux/fedora/Sunshine.spec @@ -97,9 +97,6 @@ tar -xzf %{SOURCE0} -C %{_builddir}/Sunshine # list directory ls -a %{_builddir}/Sunshine -# patches -%autopatch -p1 - %build # exit on error set -e diff --git a/packaging/linux/flatpak/deps/flatpak-builder-tools b/packaging/linux/flatpak/deps/flatpak-builder-tools index 903919f8..7090720d 160000 --- a/packaging/linux/flatpak/deps/flatpak-builder-tools +++ b/packaging/linux/flatpak/deps/flatpak-builder-tools @@ -1 +1 @@ -Subproject commit 903919f82f4cd6356bb4e9afe2755e44e8d8d7da +Subproject commit 7090720d43404c60b88445a3149835ec3c585717 diff --git a/packaging/linux/flatpak/deps/shared-modules b/packaging/linux/flatpak/deps/shared-modules index 756091e3..b63062b3 160000 --- a/packaging/linux/flatpak/deps/shared-modules +++ b/packaging/linux/flatpak/deps/shared-modules @@ -1 +1 @@ -Subproject commit 756091e3d5d6582bec4e270184319e59c04ab365 +Subproject commit b63062b3cdf451e537ed6ca1f68f9c2701ad8a98 diff --git a/packaging/linux/flatpak/scripts/additional-install.sh b/packaging/linux/flatpak/scripts/additional-install.sh index a27db4e0..06c5835e 100644 --- a/packaging/linux/flatpak/scripts/additional-install.sh +++ b/packaging/linux/flatpak/scripts/additional-install.sh @@ -2,12 +2,12 @@ # User Service mkdir -p ~/.config/systemd/user -cp /app/share/sunshine/systemd/user/sunshine.service $HOME/.config/systemd/user/sunshine.service -echo Sunshine User Service has been installed. -echo Use [systemctl --user enable sunshine] once to autostart Sunshine on login. +cp "/app/share/sunshine/systemd/user/sunshine.service" "$HOME/.config/systemd/user/sunshine.service" +echo "Sunshine User Service has been installed." +echo "Use [systemctl --user enable sunshine] once to autostart Sunshine on login." # Udev rule UDEV=$(cat /app/share/sunshine/udev/rules.d/60-sunshine.rules) -echo Configuring mouse permission. +echo "Configuring mouse permission." flatpak-spawn --host pkexec sh -c "echo '$UDEV' > /etc/udev/rules.d/60-sunshine.rules" -echo Restart computer for mouse permission to take effect. +echo "Restart computer for mouse permission to take effect." diff --git a/packaging/linux/flatpak/scripts/remove-additional-install.sh b/packaging/linux/flatpak/scripts/remove-additional-install.sh index 27d7af03..ea2680ef 100644 --- a/packaging/linux/flatpak/scripts/remove-additional-install.sh +++ b/packaging/linux/flatpak/scripts/remove-additional-install.sh @@ -2,10 +2,10 @@ # User Service systemctl --user stop sunshine -rm $HOME/.config/systemd/user/sunshine.service +rm "$HOME/.config/systemd/user/sunshine.service" systemctl --user daemon-reload -echo Sunshine User Service has been removed. +echo "Sunshine User Service has been removed." # Udev rule flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/60-sunshine.rules" -echo Input rules removed. Restart computer to take effect. +echo "Input rules removed. Restart computer to take effect." diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index ad7b46ee..97eb9fe5 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -29,9 +29,8 @@ class @PROJECT_NAME@ < Formula depends_on "cmake" => :build depends_on "doxygen" => :build depends_on "graphviz" => :build - depends_on "ninja" => :build depends_on "node" => :build - depends_on "pkg-config" => :build + depends_on "pkgconf" => :build depends_on "curl" depends_on "miniupnpc" depends_on "openssl" @@ -39,25 +38,8 @@ class @PROJECT_NAME@ < Formula depends_on "icu4c" => :recommended on_linux do - # the "build" dependencies are for libayatana-appindicator - depends_on "at-spi2-core" => :build - depends_on "cairo" => :build - depends_on "fontconfig" => :build - depends_on "freetype" => :build - depends_on "fribidi" => :build - depends_on "gettext" => :build - depends_on "gobject-introspection" => :build - depends_on "graphite2" => :build - depends_on "gtk+3" => :build - depends_on "harfbuzz" => :build - depends_on "intltool" => :build - depends_on "libepoxy" => :build - depends_on "libxdamage" => :build - depends_on "libxkbcommon" => :build - depends_on "pango" => :build - depends_on "perl" => :build - depends_on "pixman" => :build depends_on "avahi" + depends_on "libayatana-appindicator" depends_on "libcap" depends_on "libdrm" depends_on "libnotify" @@ -75,128 +57,6 @@ class @PROJECT_NAME@ < Formula depends_on "pulseaudio" depends_on "systemd" depends_on "wayland" - - # resources that do not have brew packages - resource "libayatana-appindicator" do - url "https://github.com/AyatanaIndicators/libayatana-appindicator/archive/refs/tags/0.5.94.tar.gz" - sha256 "884a6bc77994c0b58c961613ca4c4b974dc91aa0f804e70e92f38a542d0d0f90" - end - - resource "libdbusmenu" do - url "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz" - sha256 "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a" - - patch 'From 729546c51806a1b3ea6cb6efb7a115b1baa811f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Stefan=20Br=C3=BCns?= -Date: Mon, 18 Nov 2019 19:58:53 +0100 -Subject: [PATCH 1/1] Fix HAVE_VALGRIND AM_CONDITIONAL - -The AM_CONDITIONAL should also be run with --disable-tests, otherwise -HAVE_VALGRIND is undefined. ---- - configure | 4 ++-- - configure.ac | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/configure b/configure -index 831a3bb..8913b9b 100644 ---- a/configure -+++ b/configure -@@ -14801,6 +14801,8 @@ else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - $as_echo "yes" >&6; } - have_valgrind=yes -+fi -+ - fi - if test "x$have_valgrind" = "xyes"; then - HAVE_VALGRIND_TRUE= -@@ -14811,8 +14813,6 @@ else - fi - - --fi -- - - - -diff --git a/configure.ac b/configure.ac -index ace54d1..cbd38a6 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -120,8 +120,8 @@ PKG_CHECK_MODULES(DBUSMENUTESTS, json-glib-1.0 >= $JSON_GLIB_REQUIRED_VERSION - [have_tests=yes] - ) - PKG_CHECK_MODULES(DBUSMENUTESTSVALGRIND, valgrind, have_valgrind=yes, have_valgrind=no) --AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"]) - ]) -+AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"]) - - AC_SUBST(DBUSMENUTESTS_CFLAGS) - AC_SUBST(DBUSMENUTESTS_LIBS) --- -2.46.2 - - -' - end - - resource "ayatana-ido" do - url "https://github.com/AyatanaIndicators/ayatana-ido/archive/refs/tags/0.10.4.tar.gz" - sha256 "bd59abd5f1314e411d0d55ce3643e91cef633271f58126be529de5fb71c5ab38" - - patch 'From 8a09e6ad33c58c017c0c8fd756da036fc39428ea Mon Sep 17 00:00:00 2001 -From: Alexander Koskovich -Date: Sun, 29 Sep 2024 13:47:54 -0400 -Subject: [PATCH 1/1] Make introspection configurable - ---- - CMakeLists.txt | 1 + - src/CMakeLists.txt | 4 ++++ - 2 files changed, 5 insertions(+) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 0e13fcd..f3e9ec0 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -12,6 +12,7 @@ endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - option(ENABLE_TESTS "Enable all tests and checks" OFF) - option(ENABLE_COVERAGE "Enable coverage reports (includes enabling all tests and checks)" OFF) - option(ENABLE_WERROR "Treat all build warnings as errors" OFF) -+option(ENABLE_INTROSPECTION "Enable introspection" ON) - - if(ENABLE_COVERAGE) - set(ENABLE_TESTS ON) -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 5b3638d..aca9481 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -108,6 +108,8 @@ install(TARGETS "ayatana-ido3-0.4" LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIB - - # AyatanaIdo3-0.4.gir - -+if (ENABLE_INTROSPECTION) -+ - find_package(GObjectIntrospection REQUIRED QUIET) - - if (INTROSPECTION_FOUND) -@@ -183,3 +185,5 @@ if (INTROSPECTION_FOUND) - endif () - - endif () -+ -+endif () --- -2.46.2 - - -' - end - - resource "libayatana-indicator" do - url "https://github.com/AyatanaIndicators/libayatana-indicator/archive/refs/tags/0.9.4.tar.gz" - sha256 "a18d3c682e29afd77db24366f8475b26bda22b0e16ff569a2ec71cd6eb4eac95" - end end def install @@ -206,7 +66,7 @@ index 5b3638d..aca9481 100644 args = %W[ -DBUILD_WERROR=ON - -DCMAKE_CXX_STANDARD=20 + -DCMAKE_CXX_STANDARD=23 -DCMAKE_INSTALL_PREFIX=#{prefix} -DHOMEBREW_ALLOW_FETCHCONTENT=ON -DOPENSSL_ROOT_DIR=#{Formula["openssl"].opt_prefix} @@ -248,59 +108,6 @@ index 5b3638d..aca9481 100644 args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux? args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac? - # Handle system tray on Linux - if OS.linux? - # Build and install libayatana components - - # Build libdbusmenu - resource("libdbusmenu").stage do - system "./configure", - "--prefix=#{prefix}", - "--with-gtk=3", - "--disable-dumper", - "--disable-static", - "--disable-tests", - "--disable-gtk-doc", - "--enable-introspection=no", - "--disable-vala" - system "make", "install" - end - - # Build ayatana-ido - resource("ayatana-ido").stage do - system "cmake", "-S", ".", "-B", "build", "-G", "Ninja", - "-DCMAKE_INSTALL_PREFIX=#{prefix}", - "-DENABLE_INTROSPECTION=OFF", - *std_cmake_args - system "ninja", "-C", "build" - system "ninja", "-C", "build", "install" - end - - # Build libayatana-indicator - resource("libayatana-indicator").stage do - ENV.append_path "PKG_CONFIG_PATH", "#{lib}/pkgconfig" - ENV.append "LDFLAGS", "-L#{lib}" - - system "cmake", "-S", ".", "-B", "build", "-G", "Ninja", - "-DCMAKE_INSTALL_PREFIX=#{prefix}", - *std_cmake_args - system "ninja", "-C", "build" - system "ninja", "-C", "build", "install" - end - - # Build libayatana-appindicator - resource("libayatana-appindicator").stage do - system "cmake", "-S", ".", "-B", "build", "-G", "Ninja", - "-DCMAKE_INSTALL_PREFIX=#{prefix}", - "-DENABLE_BINDINGS_MONO=OFF", - "-DENABLE_BINDINGS_VALA=OFF", - "-DENABLE_GTKDOC=OFF", - *std_cmake_args - system "ninja", "-C", "build" - system "ninja", "-C", "build", "install" - end - end - system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles", *std_cmake_args, *args diff --git a/scripts/icons/convert_and_pack.sh b/scripts/icons/convert_and_pack.sh index e2bae63f..0ce197d1 100644 --- a/scripts/icons/convert_and_pack.sh +++ b/scripts/icons/convert_and_pack.sh @@ -1,61 +1,63 @@ -#!/bin/bash - -if ! [ -x "$(command -v ./go-png2ico)" ]; then - echo "./go-png2ico not found" - echo "download the executable from https://github.com/J-Siu/go-png2ico" - echo "and drop it in this folder" - exit 1 -fi - -if ! [ -x "$(command -v ./oxipng)" ]; then - echo "./oxipng executable not found" - echo "download the executable from https://github.com/shssoichiro/oxipng" - echo "and drop it in this folder" - exit 1 -fi - -if ! [ -x "$(command -v inkscape)" ]; then - echo "inkscape executable not found" - exit 1 -fi - -icon_base_sizes=(16 64) -icon_sizes_keys=() # associative array to prevent duplicates -icon_sizes_keys[256]=1 - -for icon_base_size in ${icon_base_sizes[@]}; do - # increment in 25% till 400% - icon_size_increment=$((icon_base_size / 4)) - for ((i = 0; i <= 12; i++)); do - icon_sizes_keys[$((icon_base_size + i * icon_size_increment))]=1 - done -done - -# convert to normal array -icon_sizes=${!icon_sizes_keys[@]} - -echo "using icon sizes:" -echo ${icon_sizes[@]} - -src_vectors=("../../src_assets/common/assets/web/public/images/apollo-locked.svg" - "../../src_assets/common/assets/web/public/images/apollo-pausing.svg" - "../../src_assets/common/assets/web/public/images/apollo-playing.svg" - "../../apollo.svg") - -echo "using sources vectors:" -echo ${src_vectors[@]} - -for src_vector in ${src_vectors[@]}; do - file_name=`basename "$src_vector" .svg` - png_files=() - for icon_size in ${icon_sizes[@]}; do - png_file="${file_name}${icon_size}.png" - echo "converting ${png_file}" - inkscape -w $icon_size -h $icon_size "$src_vector" --export-filename "${png_file}" && - ./oxipng -o max --strip safe --alpha "${png_file}" && - png_files+=("${png_file}") - done - - echo "packing ${file_name}.ico" - ./go-png2ico "${png_files[@]}" "${file_name}.ico" -done +#!/bin/bash + +if ! [ -x "$(command -v ./go-png2ico)" ]; then + echo "./go-png2ico not found" + echo "download the executable from https://github.com/J-Siu/go-png2ico" + echo "and drop it in this folder" + exit 1 +fi + +if ! [ -x "$(command -v ./oxipng)" ]; then + echo "./oxipng executable not found" + echo "download the executable from https://github.com/shssoichiro/oxipng" + echo "and drop it in this folder" + exit 1 +fi + +if ! [ -x "$(command -v inkscape)" ]; then + echo "inkscape executable not found" + exit 1 +fi + +icon_base_sizes=(16 64) +icon_sizes_keys=() # associative array to prevent duplicates +icon_sizes_keys[256]=1 + +for icon_base_size in "${icon_base_sizes[@]}"; do + # increment in 25% till 400% + icon_size_increment=$((icon_base_size / 4)) + for ((i = 0; i <= 12; i++)); do + icon_sizes_keys[icon_base_size + i * icon_size_increment]=1 + done +done + +# convert to normal array +icon_sizes=("${!icon_sizes_keys[@]}") + +echo "using icon sizes:" +# shellcheck disable=SC2068 # intentionally word split +echo ${icon_sizes[@]} + +src_vectors=("../../src_assets/common/assets/web/public/images/apollo-locked.svg" + "../../src_assets/common/assets/web/public/images/apollo-pausing.svg" + "../../src_assets/common/assets/web/public/images/apollo-playing.svg" + "../../apollo.svg") + +echo "using sources vectors:" +# shellcheck disable=SC2068 # intentionally word split +echo ${src_vectors[@]} + +for src_vector in "${src_vectors[@]}"; do + file_name=$(basename "${src_vector}" .svg) + png_files=() + for icon_size in "${icon_sizes[@]}"; do + png_file="${file_name}${icon_size}.png" + echo "converting ${png_file}" + inkscape -w "${icon_size}" -h "${icon_size}" "${src_vector}" --export-filename "${png_file}" && + ./oxipng -o max --strip safe --alpha "${png_file}" && + png_files+=("${png_file}") + done + + echo "packing ${file_name}.ico" + ./go-png2ico "${png_files[@]}" "${file_name}.ico" +done diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 66d0e9c8..646619ec 100644 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -96,9 +96,11 @@ function add_arch_deps() { 'base-devel' 'cmake' 'curl' + 'doxygen' "gcc${gcc_version}" "gcc${gcc_version}-libs" 'git' + 'graphviz' 'libayatana-appindicator' 'libcap' 'libdrm' @@ -406,7 +408,7 @@ function run_install() { for file in "${gcc_alternative_files[@]}"; do file_path="/etc/alternatives/$file" if [ -e "$file_path" ]; then - mv "$file_path" "$file_path.bak" + ${sudo_cmd} mv "$file_path" "$file_path.bak" fi done @@ -445,12 +447,14 @@ function run_install() { echo "Compiling doxygen" doxygen_url="https://github.com/doxygen/doxygen/releases/download/Release_${_doxygen_min}/doxygen-${doxygen_min}.src.tar.gz" echo "doxygen url: ${doxygen_url}" - wget "$doxygen_url" --progress=bar:force:noscroll -q --show-progress -O "${build_dir}/doxygen.tar.gz" - tar -xzf "${build_dir}/doxygen.tar.gz" - cd "doxygen-${doxygen_min}" - cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="." - ninja -C "build" -j"${num_processors}" - ninja -C "build" install + pushd "${build_dir}" + wget "$doxygen_url" --progress=bar:force:noscroll -q --show-progress -O "doxygen.tar.gz" + tar -xzf "doxygen.tar.gz" + cd "doxygen-${doxygen_min}" + cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="." + ninja -C "build" -j"${num_processors}" + ${sudo_cmd} ninja -C "build" install + popd else echo "Doxygen version not in range, skipping docs" cmake_args+=("-DBUILD_DOCS=OFF") @@ -462,6 +466,8 @@ function run_install() { nvm_url="https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh" echo "nvm url: ${nvm_url}" wget -qO- ${nvm_url} | bash + + # shellcheck source=/dev/null # we don't care that shellcheck cannot find nvm.sh source "$HOME/.nvm/nvm.sh" nvm install node nvm use node diff --git a/src/config.cpp b/src/config.cpp index 08613b14..f30596d5 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -34,7 +34,7 @@ #include "platform/windows/utils.h" #endif -#ifndef __APPLE__ +#if !defined(__ANDROID__) && !defined(__APPLE__) // For NVENC legacy constants #include #endif @@ -511,6 +511,7 @@ namespace config { }, // display_device 0, // max_bitrate + 0, // minimum_fps_target (0 = framerate) "1920x1080x60", // fallback_mode false, // isolated Display @@ -1085,9 +1086,12 @@ namespace config { } void apply_config(std::unordered_map &&vars) { +#ifndef __ANDROID__ + // TODO: Android can possibly support this if (!fs::exists(stream.file_apps.c_str())) { fs::copy_file(SUNSHINE_ASSETS_DIR "/apps.json", stream.file_apps); } +#endif for (auto &[name, val] : vars) { #ifdef _WIN32 @@ -1121,7 +1125,7 @@ namespace config { bool_f(vars, "nvenc_opengl_vulkan_on_dxgi", video.nv_opengl_vulkan_on_dxgi); bool_f(vars, "nvenc_latency_over_power", video.nv_sunshine_high_power_mode); -#ifndef __APPLE__ +#if !defined(__ANDROID__) && !defined(__APPLE__) video.nv_legacy.preset = video.nv.quality_preset + 11; video.nv_legacy.multipass = video.nv.two_pass == nvenc::nvenc_two_pass::quarter_resolution ? NV_ENC_TWO_PASS_QUARTER_RESOLUTION : video.nv.two_pass == nvenc::nvenc_two_pass::full_resolution ? NV_ENC_TWO_PASS_FULL_RESOLUTION : @@ -1198,6 +1202,8 @@ namespace config { } int_f(vars, "max_bitrate", video.max_bitrate); + double_between_f(vars, "minimum_fps_target", video.minimum_fps_target, {0.0, 1000.0}); + string_f(vars, "fallback_mode", video.fallback_mode); bool_f(vars, "isolated_virtual_display_option", video.isolated_virtual_display_option); bool_f(vars, "ignore_encoder_probe_failure", video.ignore_encoder_probe_failure); diff --git a/src/config.h b/src/config.h index c1f73b54..bec1ac95 100644 --- a/src/config.h +++ b/src/config.h @@ -144,6 +144,7 @@ namespace config { } dd; int max_bitrate; // Maximum bitrate, sets ceiling in kbps for bitrate requested from client + double minimum_fps_target; ///< Lowest framerate that will be used when streaming. Range 0-1000, 0 = half of client's requested framerate. std::string fallback_mode; bool isolated_virtual_display_option; diff --git a/src/logging.cpp b/src/logging.cpp index ce97197c..c9d682f8 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -16,11 +16,17 @@ #include #include #include -#include // local includes #include "logging.h" +// conditional includes +#ifdef __ANDROID__ + #include +#else + #include +#endif + extern "C" { #include } @@ -98,6 +104,48 @@ namespace logging { os << "["sv << std::put_time(<, "%Y-%m-%d %H:%M:%S.") << boost::format("%03u") % ms.count() << "]: "sv << log_type << view.attribute_values()[message].extract(); } +#ifdef __ANDROID__ + namespace sinks = boost::log::sinks; + namespace expr = boost::log::expressions; + + void android_log(const std::string &message, int severity) { + android_LogPriority android_priority; + switch (severity) { + case 0: + android_priority = ANDROID_LOG_VERBOSE; + break; + case 1: + android_priority = ANDROID_LOG_DEBUG; + break; + case 2: + android_priority = ANDROID_LOG_INFO; + break; + case 3: + android_priority = ANDROID_LOG_WARN; + break; + case 4: + android_priority = ANDROID_LOG_ERROR; + break; + case 5: + android_priority = ANDROID_LOG_FATAL; + break; + default: + android_priority = ANDROID_LOG_UNKNOWN; + break; + } + __android_log_print(android_priority, "Sunshine", "%s", message.c_str()); + } + + // custom sink backend for android + struct android_sink_backend: public sinks::basic_sink_backend { + void consume(const bl::record_view &rec) { + int log_sev = rec[severity].get(); + const std::string log_msg = rec[expr::smessage].get(); + // log to android + android_log(log_msg, log_sev); + } + }; +#endif [[nodiscard]] std::unique_ptr init(int min_log_level, const std::string &log_file) { if (sink) { @@ -120,15 +168,18 @@ namespace logging { } } +#ifndef __ANDROID__ setup_av_logging(min_log_level); setup_libdisplaydevice_logging(min_log_level); +#endif sink = boost::make_shared(); #ifndef SUNSHINE_TESTS boost::shared_ptr stream {&std::cout, boost::null_deleter()}; sink->locked_backend()->add_stream(stream); - #endif +#endif + sink->locked_backend()->add_stream(boost::make_shared(log_file)); sink->set_filter(severity >= min_log_level); sink->set_formatter(&formatter); @@ -138,9 +189,15 @@ namespace logging { sink->locked_backend()->auto_flush(true); bl::core::get()->add_sink(sink); + +#ifdef __ANDROID__ + auto android_sink = boost::make_shared>(); + bl::core::get()->add_sink(android_sink); +#endif return std::make_unique(); } +#ifndef __ANDROID__ void setup_av_logging(int min_log_level) { if (min_log_level >= 1) { av_log_set_level(AV_LOG_QUIET); @@ -198,6 +255,7 @@ namespace logging { } }); } +#endif void log_flush() { if (sink) { diff --git a/src/video.cpp b/src/video.cpp index b720b2c5..2156911d 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1922,10 +1922,12 @@ namespace video { } }); - // set minimum frame time based on client-requested target framerate - auto minimum_frame_time = std::chrono::nanoseconds(1000ms) * 1000 / config.encodingFramerate; + // set minimum frame time based on client-requested target framerate// set max frame time based on client-requested target framerate. + double minimum_fps_target = (config::video.minimum_fps_target > 0.0) ? config::video.minimum_fps_target : config.encodingFramerate; + auto max_frametime = std::chrono::nanoseconds(1000ms) * 1000 / minimum_fps_target; auto encode_frame_threshold = std::chrono::nanoseconds(1000ms) * 1000 / config.encodingFramerate; auto frame_variation_threshold = encode_frame_threshold / 4; + BOOST_LOG(info) << "Minimum FPS target set to ~"sv << (minimum_fps_target / 2) << "fps ("sv << max_frametime.count() * 2 << "ns)"sv; BOOST_LOG(info) << "Encoding Frame threshold: "sv << encode_frame_threshold; auto shutdown_event = mail->event(mail::shutdown); @@ -1997,7 +1999,7 @@ namespace video { // Encode at a minimum FPS to avoid image quality issues with static content if (!requested_idr_frame || images->peek()) { - if (auto img = images->pop(minimum_frame_time)) { + if (auto img = images->pop(max_frametime)) { frame_timestamp = img->frame_timestamp; // If new frame comes in way too fast, just drop if (*frame_timestamp < (next_frame_start - frame_variation_threshold)) { diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index 11f94d81..c0cb4873 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -208,6 +208,7 @@ "double_refreshrate": "disabled", "dd_wa_hdr_toggle_delay": 0, "max_bitrate": 0, + "minimum_fps_target": 0, "isolated_virtual_display_option": "disabled", }, }, diff --git a/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue b/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue index 69784006..4b7b72e0 100644 --- a/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue +++ b/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue @@ -1,6 +1,7 @@