diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 540e980efd4..970191bc1a8 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -9,6 +9,10 @@ on: branches: [master, nightly] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: github_env: name: GitHub Env Debug @@ -185,7 +189,7 @@ jobs: elif [[ ${{ github.ref == 'refs/heads/nightly' }} ]]; then sub_version=".r${commit}" - echo "aur_publish=true" >> $GITHUB_ENV + echo "aur_publish=false" >> $GITHUB_ENV fi else echo "This is a PR event" @@ -388,7 +392,8 @@ jobs: libboost-filesystem1.71-dev \ libboost-log1.71-dev \ libboost-regex1.71-dev \ - libboost-thread1.71-dev + libboost-thread1.71-dev \ + libboost-program-options1.71-dev # Install cmake wget https://cmake.org/files/v3.22/cmake-3.22.2-linux-x86_64.sh @@ -412,7 +417,8 @@ jobs: cmake \ libboost-filesystem-dev \ libboost-log-dev \ - libboost-thread-dev + libboost-thread-dev \ + libboost-program-options-dev fi sudo apt-get install -y \ @@ -466,9 +472,7 @@ jobs: mkdir -p build mkdir -p artifacts - pushd "./src_assets/common/assets/web" npm install - popd cd build cmake -DCMAKE_BUILD_TYPE=Release \ @@ -588,9 +592,7 @@ jobs: - name: Build MacOS run: | - pushd "./src_assets/common/assets/web" npm install - popd mkdir build cd build @@ -888,12 +890,11 @@ jobs: mingw-w64-x86_64-openssl mingw-w64-x86_64-opus mingw-w64-x86_64-toolchain - mingw-w64-x86_64-x265 nasm + wget yasm - name: Install npm packages - working-directory: src_assets/common/assets/web run: | npm install @@ -906,7 +907,7 @@ jobs: -DSUNSHINE_ASSETS_DIR=assets \ -G "MinGW Makefiles" \ .. - mingw32-make -j2 + mingw32-make -j$(nproc) - name: Package Windows shell: msys2 {0} diff --git a/.github/workflows/auto-create-pr.yml b/.github/workflows/auto-create-pr.yml index 67045e0ea9a..811747c6517 100644 --- a/.github/workflows/auto-create-pr.yml +++ b/.github/workflows/auto-create-pr.yml @@ -3,6 +3,9 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# This workflow creates a PR automatically when anything is merged/pushed into the `nightly` branch. The PR is created +# against the `master` (default) branch. + name: Auto create PR on: diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index c91ac7d4ad1..4774eb21317 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# This workflow will, first, automatically approve PRs created by @LizardByte-bot. Then it will automerge relevant PRs. + name: Automerge PR on: @@ -11,6 +13,10 @@ on: - opened - synchronize +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: autoapprove: if: >- @@ -40,9 +46,6 @@ jobs: if: startsWith(github.repository, 'LizardByte/') needs: [autoapprove] runs-on: ubuntu-latest - concurrency: - group: automerge-${{ github.ref }} - cancel-in-progress: true steps: - name: Automerging @@ -51,7 +54,7 @@ jobs: BASE_BRANCHES: nightly GITHUB_TOKEN: ${{ secrets.GH_BOT_TOKEN }} GITHUB_LOGIN: ${{ secrets.GH_BOT_NAME }} - MERGE_LABELS: "" + MERGE_LABELS: "!dependencies" MERGE_METHOD: "squash" MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})" MERGE_DELETE_BRANCH: true diff --git a/.github/workflows/autoupdate-labeler.yml b/.github/workflows/autoupdate-labeler.yml index 92b00988c89..974c9fa7fd1 100644 --- a/.github/workflows/autoupdate-labeler.yml +++ b/.github/workflows/autoupdate-labeler.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Label PRs with `autoupdate` if various conditions are met, otherwise, remove the label. + name: Label PR autoupdate on: @@ -10,11 +12,8 @@ on: types: - edited - opened + - reopened - synchronize - pull_request_review: - types: - - edited - - submitted jobs: label_pr: @@ -40,12 +39,7 @@ jobs: steps.org_member.outputs.result == 'true' && contains(github.event.pull_request.labels.*.name, 'autoupdate') == false && contains(github.event.pull_request.body, - fromJSON('"\n- [x] I want maintainers to keep my branch updated"')) == true && - ( - (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') || - (github.event_name == 'pull_request') - ) - + fromJSON('"\n- [x] I want maintainers to keep my branch updated"')) == true uses: actions/github-script@v6 with: github-token: ${{ secrets.GH_BOT_TOKEN }} @@ -60,7 +54,6 @@ jobs: - name: Unlabel autoupdate if: >- contains(github.event.pull_request.labels.*.name, 'autoupdate') && - github.event_name == 'pull_request' && ( (github.event.action == 'synchronize' && steps.org_member.outputs.result == 'false') || (contains(github.event.pull_request.body, diff --git a/.github/workflows/autoupdate.yml b/.github/workflows/autoupdate.yml index 4522182f9a3..65d80dc3fb3 100644 --- a/.github/workflows/autoupdate.yml +++ b/.github/workflows/autoupdate.yml @@ -7,8 +7,9 @@ # - automerge # - autoupdate-labeler -# It uses GitHub Action that auto-updates pull requests branches, when changes are pushed to their destination branch. +# It uses an action that auto-updates pull requests branches, when changes are pushed to their destination branch. # Auto-updating to the latest destination branch works only in the context of upstream repo and not forks. +# Dependabot PRs are updated by an action that comments `@depdenabot rebase` on dependabot PRs. name: autoupdate @@ -36,8 +37,7 @@ jobs: dependabot-rebase: name: Dependabot Rebase if: >- - startsWith(github.repository, 'LizardByte/') && - contains(github.event.pull_request.labels.*.name, 'central_dependency') == false + startsWith(github.repository, 'LizardByte/') runs-on: ubuntu-latest steps: - name: rebase diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index f1e94794151..8ff84aaac90 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -3,6 +3,10 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# This workflow is intended to work with all our organization Docker projects. Docker platforms/architectures should be +# listed in a file named `.docker_platforms`, comma separated list with no spaces. A readme named `DOCKER_README.md` +# will be used to update the description on Docker hub. + name: CI Docker on: @@ -13,6 +17,10 @@ on: branches: [master, nightly] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check_dockerfile: name: Check Dockerfile diff --git a/.github/workflows/cpp-clang-format-lint.yml b/.github/workflows/cpp-clang-format-lint.yml deleted file mode 100644 index b0b87f9eaaa..00000000000 --- a/.github/workflows/cpp-clang-format-lint.yml +++ /dev/null @@ -1,60 +0,0 @@ ---- -# This action is centrally managed in https://github.com//.github/ -# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in -# the above-mentioned repo. - -name: Clang Format Lint - -on: - pull_request: - branches: [master, nightly] - types: [opened, synchronize, reopened] - -jobs: - check_src: - name: Check src - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Check - id: check - run: | - if [ -d "./src" ] - then - FOUND=true - else - FOUND=false - fi - - echo "src=${FOUND}" >> $GITHUB_OUTPUT - - outputs: - src: ${{ steps.check.outputs.src }} - - lint: - name: Clang Format Lint - needs: [check_src] - if: ${{ needs.check_src.outputs.src == 'true' }} - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Clang format lint - uses: DoozyX/clang-format-lint-action@v0.15 - with: - source: './src' - extensions: 'cpp,h,m,mm' - clangFormatVersion: 13 - style: file - inplace: false - - - name: Upload Artifacts - if: failure() - uses: actions/upload-artifact@v3 - with: - name: clang-format-fixes - path: src/ diff --git a/.github/workflows/cpp-lint.yml b/.github/workflows/cpp-lint.yml new file mode 100644 index 00000000000..fb1bf642dea --- /dev/null +++ b/.github/workflows/cpp-lint.yml @@ -0,0 +1,84 @@ +--- +# This action is centrally managed in https://github.com//.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in +# the above-mentioned repo. + +# Lint c++ source files and cmake files. + +name: C++ Lint + +on: + pull_request: + branches: [master, nightly] + types: [opened, synchronize, reopened] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + clang-format: + name: Clang Format Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Find cpp files + id: cpp_files + run: | + cpp_files=$(find . -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.m" -o -iname "*.mm") + + echo "found cpp files: ${cpp_files}" + + # do not quote to keep this as a single line + echo cpp_files=${cpp_files} >> $GITHUB_OUTPUT + + - name: Clang format lint + if: ${{ steps.cpp_files.outputs.cpp_files }} + uses: DoozyX/clang-format-lint-action@v0.15 + with: + source: ${{ steps.cpp_files.outputs.cpp_files }} + extensions: 'cpp,h,m,mm' + clangFormatVersion: 15 + style: file + inplace: false + + - name: Upload Artifacts + if: failure() + uses: actions/upload-artifact@v3 + with: + name: clang-format-fixes + path: ${{ steps.cpp_files.outputs.cpp_files }} + + cmake-lint: + name: CMake Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools cmakelang + + - name: Find cmake files + id: cmake_files + run: | + cmake_files=$(find . -type f -iname "CMakeLists.txt" -o -iname "*.cmake") + + echo "found cmake files: ${cmake_files}" + + # do not quote to keep this as a single line + echo cmake_files=${cmake_files} >> $GITHUB_OUTPUT + + - name: Test with cmake-lint + run: | + cmake-lint --line-width 120 --tab-size 4 ${{ steps.cmake_files.outputs.cmake_files }} diff --git a/.github/workflows/issues-stale.yml b/.github/workflows/issues-stale.yml index 586545e8a7a..cc0e3ae86ef 100644 --- a/.github/workflows/issues-stale.yml +++ b/.github/workflows/issues-stale.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Manage stale issues and PRs. + name: Stale Issues / PRs on: @@ -16,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Stale - uses: actions/stale@v6 + uses: actions/stale@v7 with: close-issue-message: > This issue was closed because it has been stalled for 10 days with no activity. @@ -38,7 +40,7 @@ jobs: repo-token: ${{ secrets.GH_BOT_TOKEN }} - name: Invalid Template - uses: actions/stale@v6 + uses: actions/stale@v7 with: close-issue-message: > This issue was closed because the the template was not completed after 5 days. diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index db25703d1dd..d7a1025cdce 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Label and un-label actions using `../label-actions.yml`. + name: Issues on: diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 1fa3c071c6c..58243872498 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -3,12 +3,16 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Ensure PRs are made against `nightly` branch. + name: Pull Requests on: pull_request_target: types: [opened, synchronize, edited, reopened] +# no concurrency for pull_request_target events + jobs: check-pull-request: name: Check Pull Request diff --git a/.github/workflows/python-flake8.yml b/.github/workflows/python-flake8.yml index 463fb8a2033..19bcdb9d8a2 100644 --- a/.github/workflows/python-flake8.yml +++ b/.github/workflows/python-flake8.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Lint python files with flake8. + name: flake8 on: @@ -10,6 +12,10 @@ on: branches: [master, nightly] types: [opened, synchronize, reopened] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: flake8: runs-on: ubuntu-latest @@ -24,7 +30,8 @@ jobs: - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools flake8 + # pin flake8 before v6.0.0 due to removal of support for type comments (required for Python 2.7 type hints) + python -m pip install --upgrade pip setuptools "flake8<6" - name: Test with flake8 run: | diff --git a/.github/workflows/release-notifier.yml b/.github/workflows/release-notifier.yml index bea36033c35..ed7b3ef20ff 100644 --- a/.github/workflows/release-notifier.yml +++ b/.github/workflows/release-notifier.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Send release notification to various platforms. + name: Release Notifications on: diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index a8c97e3a09c..6327d5d6326 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -3,6 +3,8 @@ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in # the above-mentioned repo. +# Lint yaml files. + name: yaml lint on: @@ -10,6 +12,10 @@ on: branches: [master, nightly] types: [opened, synchronize, reopened] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: yaml-lint: runs-on: ubuntu-latest diff --git a/.gitmodules b/.gitmodules index 75dd21c9e9c..b79222a2dbe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,34 +1,44 @@ -[submodule "moonlight-common-c"] +[submodule "third-party/moonlight-common-c"] path = third-party/moonlight-common-c url = https://github.com/moonlight-stream/moonlight-common-c.git -[submodule "Simple-Web-Server"] + branch = master +[submodule "third-party/Simple-Web-Server"] path = third-party/Simple-Web-Server - url = https://github.com/loki-47-6F-64/Simple-Web-Server.git -[submodule "ViGEmClient"] + url = https://gitlab.com/eidheim/Simple-Web-Server.git + branch = master +[submodule "third-party/ViGEmClient"] path = third-party/ViGEmClient url = https://github.com/ViGEm/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 + branch = sdk/11.1 [submodule "third-party/TPCircularBuffer"] path = third-party/TPCircularBuffer url = https://github.com/michaeltyson/TPCircularBuffer -[submodule "ffmpeg-windows-x86_64"] + branch = master +[submodule "third-party/ffmpeg-windows-x86_64"] path = third-party/ffmpeg-windows-x86_64 url = https://github.com/LizardByte/build-deps branch = ffmpeg-windows-x86_64 -[submodule "ffmpeg-macos-x86_64"] +[submodule "third-party/ffmpeg-macos-x86_64"] path = third-party/ffmpeg-macos-x86_64 url = https://github.com/LizardByte/build-deps branch = ffmpeg-macos-x86_64 -[submodule "ffmpeg-linux-x86_64"] +[submodule "third-party/ffmpeg-linux-x86_64"] path = third-party/ffmpeg-linux-x86_64 url = https://github.com/LizardByte/build-deps branch = ffmpeg-linux-x86_64 -[submodule "ffmpeg-linux-aarch64"] +[submodule "third-party/ffmpeg-linux-aarch64"] path = third-party/ffmpeg-linux-aarch64 url = https://github.com/LizardByte/build-deps branch = ffmpeg-linux-aarch64 +[submodule "third-party/ffmpeg-macos-aarch64"] + path = third-party/ffmpeg-macos-aarch64 + url = https://github.com/LizardByte/build-deps + branch = ffmpeg-macos-aarch64 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e2a05cef2d..d2521b68ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,59 @@ # Changelog +## [0.17.0] - 2023-01-08 +If you are running Sunshine as a service on Windows, we are strongly urging you to update to v0.17.0 as soon as +possible. Older Windows versions of Sunshine had a security flaw in which the binary was located in a user-writable +location which is problematic when running as a service or on a multi-user system. Additionally, when running Sunshine +as a service, games and applications were launched as SYSTEM. This could lead to issues with save files and other game +settings. In v0.17.0, games now run under your user account without elevated privileges. + +### Breaking +- (Apps) Removed automatic desktop entry (Re-add by adding an empty application named "Desktop" with no commands, "desktop.png" can be added as the image.) +- (Windows) Improved user upgrade experience (Suggest to manually uninstall existing Sunshine version before this upgrade. Do NOT select to remove everything, if prompted. Make a backup of config files before uninstall.) +- (Windows) Move config files to specific directory (files will be migrated automatically if using Windows installer) +- (Dependencies) Fix npm path (breaking change for package maintainers) +### Added +- (macOS) Added initial support for arm64 on macOS through Macports portfile +- (Input) Added support for foreign keyboard input +- (Misc) Logs inside the WebUI and log to file +- (UI/Windows) Added an Apply button to configuration page when running as a service +- (Input/Windows) Enable Mouse Keys while streaming for systems with no physical mouse +### Fixed +- (Video) Improved capture performance +- (Audio) Improved audio bitrate and quality handling +- (Apps/Windows) Fixed PATH environment variable handling +- (Apps/Windows) Use the proper environment variable for the Program Files (x86) folder +- (Service/Windows) Fix SunshineSvc hanging if an error occurs during startup +- (Service/Windows) Spawn Sunshine.exe in a job object, so it is terminated if SunshineSvc.exe dies +- (Video) windows/vram: fix fringing in NV12 colour conversion +- (Apps/Windows) Launch games under the correct user account +- (Video) nvenc, amdvce: rework all user presets/options +- (Network) Generate certificates with unique serial numbers +- (Service/Windows) Graceful termination on shutdown, logoff, and service stop +- (Apps/Windows) Fix launching apps when Sunshine is running as admin +- (Misc) Remove/fix calls to std::abort() +- (Misc) Remove prompt to press enter after Sunshine exits +- (Misc) Make log priority consistent for execution messages +- (Apps) Applications in Moonlight clients are now updated automatically after editing +- (Video/Linux) Fix wayland capture on nvidia +- (Audio) Fix 7.1 surround channel mapping +- (Video) Fix NVENC profile values not applying +- (Network) Fix origin_web_ui_allowed binding +- (Service/Windows) Self terminate/restart service if process hangs for 10 seconds +- (Input/Windows) Fix Windows masked cursor blending with GPU encoders +- (Video) Color conversion fixes and BT.2020 support +### Dependencies +- Bump ffmpeg from 4.4 to 5.1 +- ffmpeg_patches: add amfenc delay/buffering fix +- CBS moved to ffmpeg submodules +- Migrate to upstream Simple-Web-Server submodule +- Bump third-party/TPCircularBuffer from `bce9170` to `8833b3a` +- Bump third-party/moonlight-common-c from `8169a31` to `ef9ad52` +- Bump third-party/miniupnp from `6f848ae` to `207cf44` +- Bump third-party/ViGEmClient from `f719a1d` to `9e842ba` +- Bump bootstrap from 5.0.0 to 5.2.3 +- Bump @fortawesome/fontawesome-free from 6.2.0 to 6.2.1 + ## [0.16.0] - 2022-12-13 ### Added - Add cover finder @@ -61,7 +115,7 @@ - (Documentation) Added Sphinx documentation available at https://sunshinestream.readthedocs.io/en/latest/ - (Development) Initial support for Localization - (Linux) Add rpm package as release asset -- (MacOS) Add Portfile as release asset +- (macOS) Add Portfile as release asset - (Windows) Add DwmFlush() call to improve capture - (Windows) Add Windows installer ### Fixed @@ -70,13 +124,13 @@ - (Linux) Fixed rumble events causing game to freeze - (Linux) Improved Pulse/Pipewire compatibility - (Linux) Moved to single deb package -- (MacOS) Fixed missing TPCircularBuffer submodule +- (macOS) Fixed missing TPCircularBuffer submodule - (Stream) Properly catch exceptions in stream broadcast handlers - (Stream/Video) AVPacket fix ## [0.13.0] - 2022-02-27 ### Added -- (MacOS) Initial support for MacOS (#40) +- (macOS) Initial support for macOS (#40) ## [0.12.0] - 2022-02-13 ### Added @@ -193,3 +247,28 @@ ## [0.1.0] - 2020-01-27 ### Added - The first official release for Sunshine! + +[0.1.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.1.0 +[0.1.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.1.1 +[0.2.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.2.0 +[0.3.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.3.0 +[0.3.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.3.1 +[0.4.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.4.0 +[0.5.0]: https://github.com/LizardByte/Sunshine/releases/tag/0.5.0 +[0.6.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.6.0 +[0.7.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.7.0 +[0.7.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.7.1 +[0.7.7]: https://github.com/LizardByte/Sunshine/releases/tag/v0.7.7 +[0.8.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.8.0 +[0.9.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.9.0 +[0.10.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.10.0 +[0.10.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.10.1 +[0.11.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.11.0 +[0.11.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.11.1 +[0.12.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.12.0 +[0.13.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.13.0 +[0.14.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.14.0 +[0.14.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.14.1 +[0.15.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.15.0 +[0.16.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.16.0 +[0.17.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.17.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index fad60ef5e16..b1970b1d224 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 3.0) -project(Sunshine VERSION 0.16.0 - DESCRIPTION "Sunshine is a Gamestream host for Moonlight." - HOMEPAGE_URL "https://app.lizardbyte.dev" - ) +project(Sunshine VERSION 0.17.0 + DESCRIPTION "Sunshine is a self-hosted game stream host for Moonlight." + HOMEPAGE_URL "https://app.lizardbyte.dev") -set(PROJECT_LONG_DESCRIPTION "Sunshine is a self hosted, low latency, cloud gaming solution with support for AMD, \ -Intel, and Nvidia GPUs. It is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield. \ -Connect to Sunshine from any Moonlight client, available for nearly any device imaginable.") +set(PROJECT_LONG_DESCRIPTION "Offering low latency, cloud gaming server capabilities with support for AMD, Intel, \ +and Nvidia GPUs for hardware encoding. Software encoding is also available. You can connect to Sunshine from any \ +Moonlight client on a variety of devices. A web UI is provided to allow configuration, and client pairing, from \ +your favorite web browser. Pair from the local server or any mobile device.") option(SUNSHINE_CONFIGURE_APPIMAGE "Configuration specific for AppImage." OFF) option(SUNSHINE_CONFIGURE_AUR "Configure files required for AUR." OFF) @@ -17,37 +17,38 @@ option(SUNSHINE_CONFIGURE_PORTFILE "Configure macOS Portfile." OFF) option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF) if(${SUNSHINE_CONFIGURE_APPIMAGE}) - configure_file(packaging/linux/sunshine.desktop sunshine.desktop @ONLY) + configure_file(packaging/linux/sunshine.desktop sunshine.desktop @ONLY) elseif(${SUNSHINE_CONFIGURE_AUR}) - configure_file(packaging/linux/aur/PKGBUILD PKGBUILD @ONLY) + configure_file(packaging/linux/aur/PKGBUILD PKGBUILD @ONLY) elseif(${SUNSHINE_CONFIGURE_FLATPAK_MAN}) - configure_file(packaging/linux/flatpak/dev.lizardbyte.sunshine.yml dev.lizardbyte.sunshine.yml @ONLY) + configure_file(packaging/linux/flatpak/dev.lizardbyte.sunshine.yml dev.lizardbyte.sunshine.yml @ONLY) elseif(${SUNSHINE_CONFIGURE_PORTFILE}) - configure_file(packaging/macos/Portfile Portfile @ONLY) + configure_file(packaging/macos/Portfile Portfile @ONLY) endif() # return if configure only is set if(${SUNSHINE_CONFIGURE_ONLY}) - return() + return() endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(SUNSHINE_SOURCE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src_assets") if(APPLE) - macro(ADD_FRAMEWORK fwname appname) - find_library(FRAMEWORK_${fwname} - NAMES ${fwname} - PATHS ${CMAKE_OSX_SYSROOT}/System/Library - PATH_SUFFIXES Frameworks - NO_DEFAULT_PATH) - if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND) - MESSAGE(ERROR ": Framework ${fwname} not found") - else() - TARGET_LINK_LIBRARIES(${appname} "${FRAMEWORK_${fwname}}/${fwname}") - MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}") - endif() - endmacro(ADD_FRAMEWORK) + # ADD_FRAMEWORK: args = `fwname`, `appname` + macro(ADD_FRAMEWORK fwname appname) + find_library(FRAMEWORK_${fwname} + NAMES ${fwname} + PATHS ${CMAKE_OSX_SYSROOT}/System/Library + PATH_SUFFIXES Frameworks + NO_DEFAULT_PATH) + if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND) + MESSAGE(ERROR ": Framework ${fwname} not found") + else() + TARGET_LINK_LIBRARIES(${appname} "${FRAMEWORK_${fwname}}/${fwname}") + MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}") + endif() + endmacro(ADD_FRAMEWORK) endif() add_subdirectory(third-party/moonlight-common-c/enet) @@ -58,7 +59,7 @@ 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(third-party/miniupnp) +include_directories(third-party/miniupnp/miniupnpc/include) find_package(Threads REQUIRED) find_package(OpenSSL REQUIRED) @@ -66,412 +67,421 @@ find_package(PkgConfig REQUIRED) pkg_check_modules (CURL REQUIRED libcurl) if(NOT APPLE) - set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_LIBS ON) # cmake-lint: disable=C0103 +endif() +if(WIN32) + # workaround to prevent link errors against icudata, icui18n + set(Boost_NO_BOOST_CMAKE ON) # cmake-lint: disable=C0103 endif() -find_package(Boost COMPONENTS log filesystem REQUIRED) + +find_package(Boost COMPONENTS log filesystem program_options REQUIRED) list(APPEND SUNSHINE_COMPILE_OPTIONS -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare) if(WIN32) - enable_language(RC) - set(CMAKE_RC_COMPILER windres) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CURL_STATIC_LDFLAGS} ${CURL_STATIC_CFLAGS}") - - # Restrict Boost WinAPI version to work around 1.80 linker errors - ADD_DEFINITIONS(-DBOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WIN7) - - add_compile_definitions(SUNSHINE_PLATFORM="windows") - add_subdirectory(tools) # This is temporary, only tools for Windows are needed, for now - - include_directories(third-party/ViGEmClient/include) - - if(NOT DEFINED SUNSHINE_ICON_PATH) - set(SUNSHINE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sunshine.ico") - endif() - configure_file(src/platform/windows/windows.rs.in windows.rc @ONLY) - set(PLATFORM_TARGET_FILES - "${CMAKE_CURRENT_BINARY_DIR}/windows.rc" - src/platform/windows/publish.cpp - src/platform/windows/misc.h - src/platform/windows/misc.cpp - src/platform/windows/input.cpp - src/platform/windows/display.h - src/platform/windows/display_base.cpp - 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) - - set(OPENSSL_LIBRARIES - libssl.a - libcrypto.a) - - list(PREPEND PLATFORM_LIBRARIES - libstdc++.a - libwinpthread.a - libssp.a - ksuser - wsock32 - ws2_32 - d3d11 dxgi D3DCompiler - setupapi - dwmapi - ${CURL_STATIC_LIBRARIES} - ) - - 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") + enable_language(RC) + set(CMAKE_RC_COMPILER windres) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CURL_STATIC_LDFLAGS} ${CURL_STATIC_CFLAGS}") + + add_compile_definitions(SUNSHINE_PLATFORM="windows") + add_subdirectory(tools) # This is temporary, only tools for Windows are needed, for now + + include_directories(third-party/ViGEmClient/include) + + if(NOT DEFINED SUNSHINE_ICON_PATH) + set(SUNSHINE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sunshine.ico") + endif() + configure_file(src/platform/windows/windows.rs.in windows.rc @ONLY) + set(PLATFORM_TARGET_FILES + "${CMAKE_CURRENT_BINARY_DIR}/windows.rc" + src/platform/windows/publish.cpp + src/platform/windows/misc.h + src/platform/windows/misc.cpp + src/platform/windows/input.cpp + src/platform/windows/display.h + src/platform/windows/display_base.cpp + 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) + + set(OPENSSL_LIBRARIES + libssl.a + libcrypto.a) + + list(PREPEND PLATFORM_LIBRARIES + libstdc++.a + libwinpthread.a + libssp.a + ksuser + wsock32 + ws2_32 + d3d11 dxgi D3DCompiler + setupapi + dwmapi + userenv + synchronization.lib + ${CURL_STATIC_LIBRARIES}) + + 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") elseif(APPLE) - add_compile_definitions(SUNSHINE_PLATFORM="macos") - - option(SUNSHINE_MACOS_PACKAGE "Should only be used when creating a MACOS package/dmg." OFF) - - link_directories(/opt/local/lib) - link_directories(/usr/local/lib) - ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK) - - FIND_LIBRARY(APP_SERVICES_LIBRARY ApplicationServices ) - FIND_LIBRARY(AV_FOUNDATION_LIBRARY AVFoundation ) - FIND_LIBRARY(CORE_MEDIA_LIBRARY CoreMedia ) - FIND_LIBRARY(CORE_VIDEO_LIBRARY CoreVideo ) - FIND_LIBRARY(VIDEO_TOOLBOX_LIBRARY VideoToolbox ) - FIND_LIBRARY(FOUNDATION_LIBRARY Foundation ) - list(APPEND SUNSHINE_EXTERNAL_LIBRARIES - ${APP_SERVICES_LIBRARY} - ${AV_FOUNDATION_LIBRARY} - ${CORE_MEDIA_LIBRARY} - ${CORE_VIDEO_LIBRARY} - ${VIDEO_TOOLBOX_LIBRARY} - ${FOUNDATION_LIBRARY}) - - set(PLATFORM_INCLUDE_DIRS - ${Boost_INCLUDE_DIR}) - - set(APPLE_PLIST_FILE ${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/Info.plist) - - set(PLATFORM_TARGET_FILES - src/platform/macos/av_audio.h - src/platform/macos/av_audio.m - src/platform/macos/av_img_t.h - src/platform/macos/av_video.h - src/platform/macos/av_video.m - src/platform/macos/display.mm - src/platform/macos/input.cpp - src/platform/macos/microphone.mm - src/platform/macos/misc.cpp - src/platform/macos/misc.h - src/platform/macos/nv12_zero_device.cpp - src/platform/macos/nv12_zero_device.h - src/platform/macos/publish.cpp - third-party/TPCircularBuffer/TPCircularBuffer.c - third-party/TPCircularBuffer/TPCircularBuffer.h - ${APPLE_PLIST_FILE}) + add_compile_definitions(SUNSHINE_PLATFORM="macos") + + option(SUNSHINE_MACOS_PACKAGE "Should only be used when creating a MACOS package/dmg." OFF) + + link_directories(/opt/local/lib) + link_directories(/usr/local/lib) + ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK) + + FIND_LIBRARY(APP_SERVICES_LIBRARY ApplicationServices ) + FIND_LIBRARY(AV_FOUNDATION_LIBRARY AVFoundation ) + FIND_LIBRARY(CORE_MEDIA_LIBRARY CoreMedia ) + FIND_LIBRARY(CORE_VIDEO_LIBRARY CoreVideo ) + FIND_LIBRARY(VIDEO_TOOLBOX_LIBRARY VideoToolbox ) + FIND_LIBRARY(FOUNDATION_LIBRARY Foundation ) + list(APPEND SUNSHINE_EXTERNAL_LIBRARIES + ${APP_SERVICES_LIBRARY} + ${AV_FOUNDATION_LIBRARY} + ${CORE_MEDIA_LIBRARY} + ${CORE_VIDEO_LIBRARY} + ${VIDEO_TOOLBOX_LIBRARY} + ${FOUNDATION_LIBRARY}) + + set(PLATFORM_INCLUDE_DIRS + ${Boost_INCLUDE_DIR}) + + set(APPLE_PLIST_FILE ${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/Info.plist) + + set(PLATFORM_TARGET_FILES + src/platform/macos/av_audio.h + src/platform/macos/av_audio.m + src/platform/macos/av_img_t.h + src/platform/macos/av_video.h + src/platform/macos/av_video.m + src/platform/macos/display.mm + src/platform/macos/input.cpp + src/platform/macos/microphone.mm + src/platform/macos/misc.cpp + src/platform/macos/misc.h + src/platform/macos/nv12_zero_device.cpp + src/platform/macos/nv12_zero_device.h + src/platform/macos/publish.cpp + third-party/TPCircularBuffer/TPCircularBuffer.c + third-party/TPCircularBuffer/TPCircularBuffer.h + ${APPLE_PLIST_FILE}) else() - add_compile_definitions(SUNSHINE_PLATFORM="linux") - - option(SUNSHINE_ENABLE_DRM "Enable KMS grab if available" ON) - option(SUNSHINE_ENABLE_X11 "Enable X11 grab if available" ON) - option(SUNSHINE_ENABLE_WAYLAND "Enable building wayland specific code" ON) - option(SUNSHINE_ENABLE_CUDA "Enable cuda specific code" ON) - - if(${SUNSHINE_ENABLE_X11}) - find_package(X11) - else() - set(X11_FOUND OFF) - endif() - - set(CUDA_FOUND OFF) - if(${SUNSHINE_ENABLE_CUDA}) - include(CheckLanguage) - check_language(CUDA) - - if(CMAKE_CUDA_COMPILER) - if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) - set(CMAKE_CUDA_ARCHITECTURES 35) - endif() - - set(CUDA_FOUND ON) - enable_language(CUDA) - endif() - endif() - if(${SUNSHINE_ENABLE_DRM}) - find_package(LIBDRM) - find_package(LIBCAP) - else() - set(LIBDRM_FOUND OFF) - set(LIBCAP_FOUND OFF) - endif() - if(${SUNSHINE_ENABLE_WAYLAND}) - find_package(Wayland) - else() - set(WAYLAND_FOUND OFF) - endif() - - if(X11_FOUND) - add_compile_definitions(SUNSHINE_BUILD_X11) - include_directories(${X11_INCLUDE_DIR}) - list(APPEND PLATFORM_TARGET_FILES src/platform/linux/x11grab.cpp) - endif() - - if(CUDA_FOUND) - include_directories(third-party/nvfbc) - list(APPEND PLATFORM_TARGET_FILES - src/platform/linux/cuda.cu - src/platform/linux/cuda.cpp - third-party/nvfbc/NvFBC.h) - - add_compile_definitions(SUNSHINE_BUILD_CUDA) - endif() - - if(LIBDRM_FOUND AND LIBCAP_FOUND) - add_compile_definitions(SUNSHINE_BUILD_DRM) - include_directories(${LIBDRM_INCLUDE_DIRS} ${LIBCAP_INCLUDE_DIRS}) - list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES} ${LIBCAP_LIBRARIES}) - list(APPEND PLATFORM_TARGET_FILES src/platform/linux/kmsgrab.cpp) - list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1) - elseif(LIBDRM_FOUND) - message(WARNING "Found libdrm, yet there is no libcap") - elseif(LIBDRM_FOUND) - message(WARNING "Found libcap, yet there is no libdrm") - endif() - - if(WAYLAND_FOUND) - add_compile_definitions(SUNSHINE_BUILD_WAYLAND) - macro(genWayland FILENAME) - make_directory(${CMAKE_BINARY_DIR}/generated-src) - - message("wayland-scanner private-code ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c") - message("wayland-scanner client-header ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h") - execute_process( - COMMAND wayland-scanner private-code ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c - COMMAND wayland-scanner client-header ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h - - RESULT_VARIABLE EXIT_INT - ) - - if(NOT ${EXIT_INT} EQUAL 0) - message(FATAL_ERROR "wayland-scanner failed") - endif() - - list(APPEND PLATFORM_TARGET_FILES - ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c - ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h - ) - endmacro() - - genWayland(xdg-output-unstable-v1) - genWayland(wlr-export-dmabuf-unstable-v1) - - include_directories( - ${WAYLAND_INCLUDE_DIRS} - ${CMAKE_BINARY_DIR}/generated-src - ) - - list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES}) - list(APPEND PLATFORM_TARGET_FILES - src/platform/linux/wlgrab.cpp - src/platform/linux/wayland.cpp) - endif() - if(NOT ${X11_FOUND} AND NOT (${LIBDRM_FOUND} AND ${LIBCAP_FOUND}) AND NOT ${WAYLAND_FOUND} AND NOT ${}) - message(FATAL_ERROR "Couldn't find either x11, wayland, cuda or (libdrm and libcap)") - endif() - - list(APPEND PLATFORM_TARGET_FILES - src/platform/linux/publish.cpp - src/platform/linux/vaapi.h - src/platform/linux/vaapi.cpp - src/platform/linux/cuda.h - src/platform/linux/graphics.h - src/platform/linux/graphics.cpp - src/platform/linux/misc.h - src/platform/linux/misc.cpp - src/platform/linux/audio.cpp - src/platform/linux/input.cpp - src/platform/linux/x11grab.h - src/platform/linux/wayland.h - third-party/glad/src/egl.c - third-party/glad/src/gl.c - third-party/glad/include/EGL/eglplatform.h - third-party/glad/include/KHR/khrplatform.h - third-party/glad/include/glad/gl.h - third-party/glad/include/glad/egl.h) - - list(APPEND PLATFORM_LIBRARIES - dl - evdev - numa - pulse - pulse-simple - ) - - include_directories( - /usr/include/libevdev-1.0 - third-party/nv-codec-headers/include - third-party/glad/include) - - if(NOT DEFINED SUNSHINE_EXECUTABLE_PATH) - set(SUNSHINE_EXECUTABLE_PATH "sunshine") - endif() - configure_file(sunshine.service.in sunshine.service @ONLY) + add_compile_definitions(SUNSHINE_PLATFORM="linux") + + option(SUNSHINE_ENABLE_DRM "Enable KMS grab if available" ON) + option(SUNSHINE_ENABLE_X11 "Enable X11 grab if available" ON) + option(SUNSHINE_ENABLE_WAYLAND "Enable building wayland specific code" ON) + option(SUNSHINE_ENABLE_CUDA "Enable cuda specific code" ON) + + if(${SUNSHINE_ENABLE_X11}) + find_package(X11) + else() + set(X11_FOUND OFF) + endif() + + set(CUDA_FOUND OFF) + if(${SUNSHINE_ENABLE_CUDA}) + include(CheckLanguage) + check_language(CUDA) + + if(CMAKE_CUDA_COMPILER) + if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) + set(CMAKE_CUDA_ARCHITECTURES 35) + endif() + + set(CUDA_FOUND ON) + enable_language(CUDA) + endif() + endif() + if(${SUNSHINE_ENABLE_DRM}) + find_package(LIBDRM) + find_package(LIBCAP) + else() + set(LIBDRM_FOUND OFF) + set(LIBCAP_FOUND OFF) + endif() + if(${SUNSHINE_ENABLE_WAYLAND}) + find_package(Wayland) + else() + set(WAYLAND_FOUND OFF) + endif() + + if(X11_FOUND) + add_compile_definitions(SUNSHINE_BUILD_X11) + include_directories(${X11_INCLUDE_DIR}) + list(APPEND PLATFORM_TARGET_FILES src/platform/linux/x11grab.cpp) + endif() + + if(CUDA_FOUND) + include_directories(third-party/nvfbc) + list(APPEND PLATFORM_TARGET_FILES + src/platform/linux/cuda.cu + src/platform/linux/cuda.cpp + third-party/nvfbc/NvFBC.h) + + add_compile_definitions(SUNSHINE_BUILD_CUDA) + endif() + + if(LIBDRM_FOUND AND LIBCAP_FOUND) + add_compile_definitions(SUNSHINE_BUILD_DRM) + include_directories(${LIBDRM_INCLUDE_DIRS} ${LIBCAP_INCLUDE_DIRS}) + list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES} ${LIBCAP_LIBRARIES}) + list(APPEND PLATFORM_TARGET_FILES src/platform/linux/kmsgrab.cpp) + list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1) + elseif(LIBDRM_FOUND) + message(WARNING "Found libdrm, yet there is no libcap") + elseif(LIBDRM_FOUND) + message(WARNING "Found libcap, yet there is no libdrm") + endif() + + if(WAYLAND_FOUND) + add_compile_definitions(SUNSHINE_BUILD_WAYLAND) + # GEN_WAYLAND: args = `filename` + macro(GEN_WAYLAND filename) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated-src) + + message("wayland-scanner private-code \ +${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${filename}.xml \ +${CMAKE_BINARY_DIR}/generated-src/${filename}.c") + message("wayland-scanner client-header \ +${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${filename}.xml \ +${CMAKE_BINARY_DIR}/generated-src/${filename}.h") + execute_process( + COMMAND wayland-scanner private-code + ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${filename}.xml + ${CMAKE_BINARY_DIR}/generated-src/${filename}.c + COMMAND wayland-scanner client-header + ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${filename}.xml + ${CMAKE_BINARY_DIR}/generated-src/${filename}.h + + RESULT_VARIABLE EXIT_INT + ) + + if(NOT ${EXIT_INT} EQUAL 0) + message(FATAL_ERROR "wayland-scanner failed") + endif() + + list(APPEND PLATFORM_TARGET_FILES + ${CMAKE_BINARY_DIR}/generated-src/${filename}.c + ${CMAKE_BINARY_DIR}/generated-src/${filename}.h) + endmacro() + + GEN_WAYLAND(xdg-output-unstable-v1) + GEN_WAYLAND(wlr-export-dmabuf-unstable-v1) + + include_directories( + ${WAYLAND_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/generated-src + ) + + list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES}) + list(APPEND PLATFORM_TARGET_FILES + src/platform/linux/wlgrab.cpp + src/platform/linux/wayland.cpp) + endif() + if(NOT ${X11_FOUND} AND NOT (${LIBDRM_FOUND} AND ${LIBCAP_FOUND}) AND NOT ${WAYLAND_FOUND} AND NOT ${}) + message(FATAL_ERROR "Couldn't find either x11, wayland, cuda or (libdrm and libcap)") + endif() + + list(APPEND PLATFORM_TARGET_FILES + src/platform/linux/publish.cpp + src/platform/linux/vaapi.h + src/platform/linux/vaapi.cpp + src/platform/linux/cuda.h + src/platform/linux/graphics.h + src/platform/linux/graphics.cpp + src/platform/linux/misc.h + src/platform/linux/misc.cpp + src/platform/linux/audio.cpp + src/platform/linux/input.cpp + src/platform/linux/x11grab.h + src/platform/linux/wayland.h + third-party/glad/src/egl.c + third-party/glad/src/gl.c + third-party/glad/include/EGL/eglplatform.h + third-party/glad/include/KHR/khrplatform.h + third-party/glad/include/glad/gl.h + third-party/glad/include/glad/egl.h) + + list(APPEND PLATFORM_LIBRARIES + dl + evdev + numa + pulse + pulse-simple) + + include_directories( + /usr/include/libevdev-1.0 + third-party/nv-codec-headers/include + third-party/glad/include) + + if(NOT DEFINED SUNSHINE_EXECUTABLE_PATH) + set(SUNSHINE_EXECUTABLE_PATH "sunshine") + endif() + configure_file(sunshine.service.in sunshine.service @ONLY) endif() configure_file(version.h.in version.h @ONLY) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SUNSHINE_TARGET_FILES - third-party/moonlight-common-c/reedsolomon/rs.c - third-party/moonlight-common-c/reedsolomon/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 - src/upnp.cpp - src/upnp.h - src/cbs.cpp - src/utility.h - src/uuid.h - src/config.h - src/config.cpp - src/main.cpp - src/main.h - src/crypto.cpp - src/crypto.h - src/nvhttp.cpp - src/nvhttp.h - src/httpcommon.cpp - src/httpcommon.h - src/confighttp.cpp - src/confighttp.h - src/rtsp.cpp - src/rtsp.h - src/stream.cpp - src/stream.h - src/video.cpp - src/video.h - src/input.cpp - src/input.h - src/audio.cpp - src/audio.h - src/platform/common.h - src/process.cpp - src/process.h - src/network.cpp - src/network.h - src/move_by_copy.h - src/task_pool.h - src/thread_pool.h - src/thread_safe.h - src/sync.h - src/round_robin.h - ${PLATFORM_TARGET_FILES}) + third-party/moonlight-common-c/reedsolomon/rs.c + third-party/moonlight-common-c/reedsolomon/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 + src/upnp.cpp + src/upnp.h + src/cbs.cpp + src/utility.h + src/uuid.h + src/config.h + src/config.cpp + src/main.cpp + src/main.h + src/crypto.cpp + src/crypto.h + src/nvhttp.cpp + src/nvhttp.h + src/httpcommon.cpp + src/httpcommon.h + src/confighttp.cpp + src/confighttp.h + src/rtsp.cpp + src/rtsp.h + src/stream.cpp + src/stream.h + src/video.cpp + src/video.h + src/input.cpp + src/input.h + src/audio.cpp + src/audio.h + src/platform/common.h + src/process.cpp + src/process.h + src/network.cpp + src/network.h + src/move_by_copy.h + src/task_pool.h + src/thread_pool.h + src/thread_safe.h + src/sync.h + src/round_robin.h + ${PLATFORM_TARGET_FILES}) set_source_files_properties(src/upnp.cpp PROPERTIES COMPILE_FLAGS -Wno-pedantic) # Pre-compiled binaries if(WIN32) - set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-windows-x86_64") - set(FFMPEG_PLATFORM_LIBRARIES mfplat ole32 strmiids mfuuid) + set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-windows-x86_64") + set(FFMPEG_PLATFORM_LIBRARIES mfplat ole32 strmiids mfuuid) elseif(APPLE) - set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-macos-x86_64") + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-macos-aarch64") + else() + set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-macos-x86_64") + endif() else() - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-linux-aarch64") - else() - set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-linux-x86_64") - endif() - set(FFMPEG_PLATFORM_LIBRARIES va va-drm va-x11 vdpau X11) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-linux-aarch64") + else() + set(FFMPEG_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/third-party/ffmpeg-linux-x86_64") + endif() + set(FFMPEG_PLATFORM_LIBRARIES va va-drm va-x11 vdpau X11) endif() set(FFMPEG_INCLUDE_DIRS - ${FFMPEG_PREPARED_BINARIES}/include) + ${FFMPEG_PREPARED_BINARIES}/include) if(EXISTS ${FFMPEG_PREPARED_BINARIES}/lib/libhdr10plus.a) - set(HDR10_PLUS_LIBRARY - ${FFMPEG_PREPARED_BINARIES}/lib/libhdr10plus.a) + set(HDR10_PLUS_LIBRARY + ${FFMPEG_PREPARED_BINARIES}/lib/libhdr10plus.a) endif() set(FFMPEG_LIBRARIES - ${FFMPEG_PREPARED_BINARIES}/lib/libavcodec.a - ${FFMPEG_PREPARED_BINARIES}/lib/libavutil.a - ${FFMPEG_PREPARED_BINARIES}/lib/libswscale.a - ${FFMPEG_PREPARED_BINARIES}/lib/libx264.a - ${FFMPEG_PREPARED_BINARIES}/lib/libx265.a - ${HDR10_PLUS_LIBRARY} - ${FFMPEG_PLATFORM_LIBRARIES}) + ${FFMPEG_PREPARED_BINARIES}/lib/libavcodec.a + ${FFMPEG_PREPARED_BINARIES}/lib/libavutil.a + ${FFMPEG_PREPARED_BINARIES}/lib/libcbs.a + ${FFMPEG_PREPARED_BINARIES}/lib/libSvtAv1Enc.a + ${FFMPEG_PREPARED_BINARIES}/lib/libswscale.a + ${FFMPEG_PREPARED_BINARIES}/lib/libx264.a + ${FFMPEG_PREPARED_BINARIES}/lib/libx265.a + ${HDR10_PLUS_LIBRARY} + ${FFMPEG_PLATFORM_LIBRARIES}) include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/third-party - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/cbs/include - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/enet/include - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/reedsolomon - ${FFMPEG_INCLUDE_DIRS} - ${PLATFORM_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/third-party + ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/enet/include + ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/reedsolomon + ${FFMPEG_INCLUDE_DIRS} + ${PLATFORM_INCLUDE_DIRS} ) -add_subdirectory(third-party/cbs) - string(TOUPPER "x${CMAKE_BUILD_TYPE}" BUILD_TYPE) if("${BUILD_TYPE}" STREQUAL "XDEBUG") - list(APPEND SUNSHINE_COMPILE_OPTIONS -O0 -ggdb3) - if(WIN32) - set_source_files_properties(src/nvhttp.cpp PROPERTIES COMPILE_FLAGS -O2) - endif() + list(APPEND SUNSHINE_COMPILE_OPTIONS -O0 -ggdb3) + if(WIN32) + set_source_files_properties(src/nvhttp.cpp PROPERTIES COMPILE_FLAGS -O2) + endif() else() - add_definitions(-DNDEBUG) - list(APPEND SUNSHINE_COMPILE_OPTIONS -O3) + add_definitions(-DNDEBUG) + list(APPEND SUNSHINE_COMPILE_OPTIONS -O3) endif() # setup assets directory if(NOT SUNSHINE_ASSETS_DIR) - set(SUNSHINE_ASSETS_DIR "assets") + set(SUNSHINE_ASSETS_DIR "assets") endif() if(UNIX) - set(SUNSHINE_ASSETS_DIR "${CMAKE_INSTALL_PREFIX}/${SUNSHINE_ASSETS_DIR}") + set(SUNSHINE_ASSETS_DIR "${CMAKE_INSTALL_PREFIX}/${SUNSHINE_ASSETS_DIR}") endif() # use relative assets path for AppImage... maybe for all unix if(${SUNSHINE_CONFIGURE_APPIMAGE}) - string(REPLACE "${CMAKE_INSTALL_PREFIX}" ".${CMAKE_INSTALL_PREFIX}" SUNSHINE_ASSETS_DIR_DEF ${SUNSHINE_ASSETS_DIR}) + string(REPLACE "${CMAKE_INSTALL_PREFIX}" ".${CMAKE_INSTALL_PREFIX}" SUNSHINE_ASSETS_DIR_DEF ${SUNSHINE_ASSETS_DIR}) else() - set(SUNSHINE_ASSETS_DIR_DEF "${SUNSHINE_ASSETS_DIR}") + set(SUNSHINE_ASSETS_DIR_DEF "${SUNSHINE_ASSETS_DIR}") endif() list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_ASSETS_DIR="${SUNSHINE_ASSETS_DIR_DEF}") - -list(APPEND CBS_EXTERNAL_LIBRARIES - cbs) - list(APPEND SUNSHINE_EXTERNAL_LIBRARIES - libminiupnpc-static - ${CBS_EXTERNAL_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - enet - opus - ${FFMPEG_LIBRARIES} - ${Boost_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${CURL_LIBRARIES} - ${PLATFORM_LIBRARIES}) + libminiupnpc-static + ${CMAKE_THREAD_LIBS_INIT} + enet + opus + ${FFMPEG_LIBRARIES} + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CURL_LIBRARIES} + ${PLATFORM_LIBRARIES}) if(NOT WIN32) - list(APPEND SUNSHINE_EXTERNAL_LIBRARIES Boost::log) + list(APPEND SUNSHINE_EXTERNAL_LIBRARIES Boost::log) endif() add_executable(sunshine ${SUNSHINE_TARGET_FILES}) if(WIN32) - set_target_properties(sunshine PROPERTIES LINK_SEARCH_START_STATIC 1) + set_target_properties(sunshine PROPERTIES LINK_SEARCH_START_STATIC 1) endif() target_link_libraries(sunshine ${SUNSHINE_EXTERNAL_LIBRARIES} ${EXTRA_LIBS}) target_compile_definitions(sunshine PUBLIC ${SUNSHINE_DEFINITIONS}) set_target_properties(sunshine PROPERTIES CXX_STANDARD 17 - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - ) + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) if(NOT DEFINED CMAKE_CUDA_STANDARD) set(CMAKE_CUDA_STANDARD 17) @@ -479,14 +489,14 @@ if(NOT DEFINED CMAKE_CUDA_STANDARD) endif() if(APPLE) - target_link_options(sunshine PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${APPLE_PLIST_FILE}) + target_link_options(sunshine PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${APPLE_PLIST_FILE}) endif() foreach(flag IN LISTS SUNSHINE_COMPILE_OPTIONS) - list(APPEND SUNSHINE_COMPILE_OPTIONS_CUDA "$<$:--compiler-options=${flag}>") + list(APPEND SUNSHINE_COMPILE_OPTIONS_CUDA "$<$:--compiler-options=${flag}>") endforeach() -target_compile_options(sunshine PRIVATE $<$:${SUNSHINE_COMPILE_OPTIONS}>;$<$:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) +target_compile_options(sunshine PRIVATE $<$:${SUNSHINE_COMPILE_OPTIONS}>;$<$:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301 # CPACK / Packaging @@ -503,162 +513,234 @@ set(CPACK_PACKAGE_ICON ${PROJECT_SOURCE_DIR}/sunshine.png) set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}") set(CPACK_STRIP_FILES YES) +# install npm modules +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/node_modules" + DESTINATION "${SUNSHINE_ASSETS_DIR}/web") + # Platform specific options if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.html - install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application) - - # Adding tools - install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi) - install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio) - install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT sunshinesvc) - - # scripts - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/firewall/" DESTINATION "scripts" COMPONENT firewall) - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/" DESTINATION "scripts" COMPONENT service) - - # Sunshine assets - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}" COMPONENT assets) - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}" COMPONENT assets) - - # set(CPACK_NSIS_MUI_HEADERIMAGE "") # TODO: image should be 150x57 bmp - set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\sunshine.ico") - set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") # The name of the directory that will be created in C:/Program files/ - string(APPEND CPACK_NSIS_DEFINES "\n RequestExecutionLevel admin") # TODO: Not sure if this is needed but it took me a while to figure out where to put this option so I'm leaving it here - - # Extra install commands - # Sets permissions on the installed folder so that we can write in it - # Install service - SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS - "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} - ExecWait 'icacls \\\"$INSTDIR\\\" /grant:r Users:\\\(OI\\\)\\\(CI\\\)\\\(F\\\)' - ExecWait '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"' - ExecWait '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"' - ") - - # Extra uninstall commands - # Uninstall service - set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS - "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS} - ExecWait '\\\"$INSTDIR\\\\scripts\\\\delete-firewall-rule.bat\\\"' - ExecWait '\\\"$INSTDIR\\\\scripts\\\\uninstall-service.bat\\\"' - MessageBox MB_YESNO|MB_ICONQUESTION 'Do you want to completely remove the directory $INSTDIR and all of its contents?' IDNO NoDelete - RMDir /r \\\"$INSTDIR\\\" ; skipped if no - NoDelete: - ") - - # Adding an option for the start menu and PATH - set(CPACK_NSIS_MODIFY_PATH "OFF") # TODO: it asks to add it to the PATH but is not working https://gitlab.kitware.com/cmake/cmake/-/issues/15635 - set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - set(CPACK_NSIS_MUI_FINISHPAGE_RUN "${CMAKE_PROJECT_NAME}.exe") - set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe") # This will be shown on the installed apps Windows settings - set(CPACK_NSIS_CREATE_ICONS_EXTRA - "${CPACK_NSIS_CREATE_ICONS_EXTRA} - CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' '\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe' - ") - set(CPACK_NSIS_DELETE_ICONS_EXTRA - "${CPACK_NSIS_DELETE_ICONS_EXTRA} - Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\${CMAKE_PROJECT_NAME}.lnk' - ") - - # Checking for previous installed versions - # set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON") # TODO: doesn't work on my machine when Sunshine is already installed - - set(CPACK_NSIS_HELP_LINK "https://docs.lizardbyte.dev/projects/sunshine/en/latest/about/installation.html") - set(CPACK_NSIS_URL_INFO_ABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}") - set(CPACK_NSIS_CONTACT "${CMAKE_PROJECT_HOMEPAGE_URL}/support") - - # Setting components groups and dependencies - # sunshine binary - set(CPACK_COMPONENT_APPLICATION_DISPLAY_NAME "${CMAKE_PROJECT_NAME}") - set(CPACK_COMPONENT_APPLICATION_DESCRIPTION "${CMAKE_PROJECT_NAME} main application.") - set(CPACK_COMPONENT_APPLICATION_GROUP "core") - set(CPACK_COMPONENT_APPLICATION_REQUIRED true) - set(CPACK_COMPONENT_APPLICATION_DEPENDS assets) - - # assets - set(CPACK_COMPONENT_ASSETS_DISPLAY_NAME "assets") - set(CPACK_COMPONENT_ASSETS_DESCRIPTION "Shaders, default box art, and web ui.") - set(CPACK_COMPONENT_ASSETS_GROUP "core") - set(CPACK_COMPONENT_ASSETS_REQUIRED true) - - # audio tool - set(CPACK_COMPONENT_AUDIO_DISPLAY_NAME "audio-info") - set(CPACK_COMPONENT_AUDIO_DESCRIPTION "CLI tool providing information about sound devices.") - set(CPACK_COMPONENT_AUDIO_GROUP "tools") - - # display tool - set(CPACK_COMPONENT_DXGI_DISPLAY_NAME "dxgi-info") - set(CPACK_COMPONENT_DXGI_DESCRIPTION "CLI tool providing information about graphics cards and displays.") - set(CPACK_COMPONENT_DXGI_GROUP "tools") - - # service - set(CPACK_COMPONENT_SUNSHINESVC_DISPLAY_NAME "sunshinesvc") - set(CPACK_COMPONENT_SUNSHINESVC_DESCRIPTION "CLI tool providing ability to enable/disable the Sunshine service.") - set(CPACK_COMPONENT_SUNSHINESVC_GROUP "tools") - - # service scripts - set(CPACK_COMPONENT_SERVICE_DISPLAY_NAME "service-scripts") - set(CPACK_COMPONENT_SERVICE_DESCRIPTION "Scripts to enable/disable the service.") - set(CPACK_COMPONENT_SERVICE_GROUP "scripts") - set(CPACK_COMPONENT_SERVICE_DEPENDS sunshinesvc) - - # firewall scripts - set(CPACK_COMPONENT_FIREWALL_DISPLAY_NAME "firewall-scripts") - set(CPACK_COMPONENT_FIREWALL_DESCRIPTION "Scripts to enable or disable firewall rules.") - set(CPACK_COMPONENT_FIREWALL_GROUP "scripts") + install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application) + + # Adding tools + install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi) + install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio) + install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT sunshinesvc) + + # scripts + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/firewall/" + DESTINATION "scripts" + COMPONENT firewall) + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/" + DESTINATION "scripts" + COMPONENT service) + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/migration/" + DESTINATION "scripts" + COMPONENT assets) + + # Sunshine assets + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}" + COMPONENT assets) + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}" + COMPONENT assets) + + # set(CPACK_NSIS_MUI_HEADERIMAGE "") # TODO: image should be 150x57 bmp + set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\sunshine.ico") + set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}") + # The name of the directory that will be created in C:/Program files/ + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") + + # Extra install commands + # Restores permissions on the install directory + # Migrates config files from the root into the new config folder + # Sets permissions on the config folder so that we can write in it + # Install service + SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS + "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} + ExecWait '\\\"$SYSDIR\\\\cmd.exe\\\" /c \\\"start https://sunshinestream.readthedocs.io/\\\"' + ExecWait 'icacls \\\"$INSTDIR\\\" /reset' + ExecWait '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"' + ExecWait 'icacls \\\"$INSTDIR\\\\config\\\" /grant:r Users:\\\(OI\\\)\\\(CI\\\)\\\(F\\\)' + ExecWait '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"' + ExecWait '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"' + MessageBox MB_YESNO|MB_ICONQUESTION 'Do you want to add/update ViGEmBus (virtual controller support)?' \ + IDNO NoController + ExecWait '\\\"$SYSDIR\\\\cmd.exe\\\" /c \\\"start https://github.com/ViGEm/ViGEmBus/releases/latest\\\"'; \ + skipped if no + NoController: + ") + + # Extra uninstall commands + # Uninstall service + set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS + "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS} + ExecWait '\\\"$INSTDIR\\\\scripts\\\\delete-firewall-rule.bat\\\"' + ExecWait '\\\"$INSTDIR\\\\scripts\\\\uninstall-service.bat\\\"' + MessageBox MB_YESNO|MB_ICONQUESTION \ + 'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \ + /SD IDNO IDNO NoDelete + RMDir /r \\\"$INSTDIR\\\"; skipped if no + NoDelete: + ") + + # Adding an option for the start menu and PATH + # TODO: it asks to add it to the PATH but is not working https://gitlab.kitware.com/cmake/cmake/-/issues/15635 + set(CPACK_NSIS_MODIFY_PATH "OFF") + set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") + # This will be shown on the installed apps Windows settings + set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe") + set(CPACK_NSIS_CREATE_ICONS_EXTRA + "${CPACK_NSIS_CREATE_ICONS_EXTRA} + CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' \ + '\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe' + ") + set(CPACK_NSIS_DELETE_ICONS_EXTRA + "${CPACK_NSIS_DELETE_ICONS_EXTRA} + Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\${CMAKE_PROJECT_NAME}.lnk' + ") + + # Checking for previous installed versions + set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON") + + set(CPACK_NSIS_HELP_LINK "https://sunshinestream.readthedocs.io/about/installation.html") + set(CPACK_NSIS_URL_INFO_ABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}") + set(CPACK_NSIS_CONTACT "${CMAKE_PROJECT_HOMEPAGE_URL}/support") + + set(CPACK_NSIS_MENU_LINKS + "https://sunshinestream.readthedocs.io" "Sunshine documentation" + "https://app.lizardbyte.dev" "LizardByte Web Site" + "https://app.lizardbyte.dev/support" "LizardByte Support") + + # Setting components groups and dependencies + # sunshine binary + set(CPACK_COMPONENT_APPLICATION_DISPLAY_NAME "${CMAKE_PROJECT_NAME}") + set(CPACK_COMPONENT_APPLICATION_DESCRIPTION "${CMAKE_PROJECT_NAME} main application.") + set(CPACK_COMPONENT_APPLICATION_GROUP "core") + set(CPACK_COMPONENT_APPLICATION_REQUIRED true) + set(CPACK_COMPONENT_APPLICATION_DEPENDS assets) + + # assets + set(CPACK_COMPONENT_ASSETS_DISPLAY_NAME "assets") + set(CPACK_COMPONENT_ASSETS_DESCRIPTION "Shaders, default box art, and web ui.") + set(CPACK_COMPONENT_ASSETS_GROUP "core") + set(CPACK_COMPONENT_ASSETS_REQUIRED true) + + # audio tool + set(CPACK_COMPONENT_AUDIO_DISPLAY_NAME "audio-info") + set(CPACK_COMPONENT_AUDIO_DESCRIPTION "CLI tool providing information about sound devices.") + set(CPACK_COMPONENT_AUDIO_GROUP "tools") + + # display tool + set(CPACK_COMPONENT_DXGI_DISPLAY_NAME "dxgi-info") + set(CPACK_COMPONENT_DXGI_DESCRIPTION "CLI tool providing information about graphics cards and displays.") + set(CPACK_COMPONENT_DXGI_GROUP "tools") + + # service + set(CPACK_COMPONENT_SUNSHINESVC_DISPLAY_NAME "sunshinesvc") + set(CPACK_COMPONENT_SUNSHINESVC_DESCRIPTION "CLI tool providing ability to enable/disable the Sunshine service.") + set(CPACK_COMPONENT_SUNSHINESVC_GROUP "tools") + + # service scripts + set(CPACK_COMPONENT_SERVICE_DISPLAY_NAME "service-scripts") + set(CPACK_COMPONENT_SERVICE_DESCRIPTION "Scripts to enable/disable the service.") + set(CPACK_COMPONENT_SERVICE_GROUP "scripts") + set(CPACK_COMPONENT_SERVICE_DEPENDS sunshinesvc) + + # firewall scripts + set(CPACK_COMPONENT_FIREWALL_DISPLAY_NAME "firewall-scripts") + set(CPACK_COMPONENT_FIREWALL_DESCRIPTION "Scripts to enable or disable firewall rules.") + set(CPACK_COMPONENT_FIREWALL_GROUP "scripts") endif() if(APPLE) - # TODO: bundle doesn't produce a valid .app use cpack -G DragNDrop - set(CPACK_BUNDLE_NAME "${CMAKE_PROJECT_NAME}") - set(CPACK_BUNDLE_PLIST "${APPLE_PLIST_FILE}") - set(CPACK_BUNDLE_ICON "${PROJECT_SOURCE_DIR}/sunshine.icns") - # set(CPACK_BUNDLE_STARTUP_COMMAND "${INSTALL_RUNTIME_DIR}/sunshine") + # TODO: bundle doesn't produce a valid .app use cpack -G DragNDrop + set(CPACK_BUNDLE_NAME "${CMAKE_PROJECT_NAME}") + set(CPACK_BUNDLE_PLIST "${APPLE_PLIST_FILE}") + set(CPACK_BUNDLE_ICON "${PROJECT_SOURCE_DIR}/sunshine.icns") + # set(CPACK_BUNDLE_STARTUP_COMMAND "${INSTALL_RUNTIME_DIR}/sunshine") endif() if(APPLE AND SUNSHINE_MACOS_PACKAGE) # TODO - set(prefix "${CMAKE_PROJECT_NAME}.app/Contents") - set(INSTALL_RUNTIME_DIR "${prefix}/MacOS") + set(MAC_PREFIX "${CMAKE_PROJECT_NAME}.app/Contents") + set(INSTALL_RUNTIME_DIR "${MAC_PREFIX}/MacOS") - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}") - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}") + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}") + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}") - install(TARGETS sunshine - BUNDLE DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} COMPONENT Runtime) + install(TARGETS sunshine + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} COMPONENT Runtime) elseif(UNIX) - # Installation destination dir - set(CPACK_SET_DESTDIR true) - if(NOT CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX "/usr/share/sunshine") - endif() - - install(TARGETS sunshine RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") - - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}") - - if(APPLE) - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}") - install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/misc/uninstall_pkg.sh" DESTINATION "${SUNSHINE_ASSETS_DIR}") - else() - install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}") - if(${SUNSHINE_CONFIGURE_APPIMAGE} OR ${SUNSHINE_CONFIGURE_FLATPAK}) - install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules" DESTINATION "${SUNSHINE_ASSETS_DIR}/udev/rules.d") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service" DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user") - else() - install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/udev/rules.d") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/systemd/user") - endif() - - # Post install - set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst") - set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst") - - # Dependencies - set(CPACK_DEB_COMPONENT_INSTALL ON) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl, libboost-thread1.67.0 | libboost-thread1.71.0 | libboost-thread1.74.0, libboost-filesystem1.67.0 | libboost-filesystem1.71.0 | libboost-filesystem1.74.0, libboost-log1.67.0 | libboost-log1.71.0 | libboost-log1.74.0, libcurl4, libpulse0, libopus0, libxcb-shm0, libxcb-xfixes0, libxtst6, libevdev2, libdrm2, libcap2") - set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.1, boost-thread >= 1.67.0, boost-filesystem >= 1.67.0, boost-log >= 1.67.0, libcurl >= 7.0, pulseaudio-libs >= 10.0, libopusenc >= 0.2.1, libxcb >= 1.13, libXtst >= 1.2.3, libevdev >= 1.5.6, libdrm >= 2.4.97, libcap >= 2.22") - set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) # This should automatically figure out dependencies, doesn't work with the current config - endif() + # Installation destination dir + set(CPACK_SET_DESTDIR true) + if(NOT CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/share/sunshine") + endif() + + install(TARGETS sunshine RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}") + + if(APPLE) + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}") + install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/misc/uninstall_pkg.sh" + DESTINATION "${SUNSHINE_ASSETS_DIR}") + else() + install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/assets/" + DESTINATION "${SUNSHINE_ASSETS_DIR}") + if(${SUNSHINE_CONFIGURE_APPIMAGE} OR ${SUNSHINE_CONFIGURE_FLATPAK}) + install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules" + DESTINATION "${SUNSHINE_ASSETS_DIR}/udev/rules.d") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service" + DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user") + else() + install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules" + DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/udev/rules.d") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service" + DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/systemd/user") + endif() + + # Post install + set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst") + set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst") + + # Dependencies + set(CPACK_DEB_COMPONENT_INSTALL ON) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ + libboost-filesystem1.67.0 | libboost-filesystem1.71.0 | libboost-filesystem1.74.0, \ + libboost-log1.67.0 | libboost-log1.71.0 | libboost-log1.74.0, \ + libboost-program-options1.67.0 | libboost-program-options1.71.0 | libboost-program-options1.74.0, \ + libboost-thread1.67.0 | libboost-thread1.71.0 | libboost-thread1.74.0, \ + libcap2, \ + libcurl4, \ + libdrm2, \ + libevdev2, \ + libopus0, \ + libpulse0, \ + libxcb-shm0, \ + libxcb-xfixes0, \ + libxtst6, \ + openssl") + set(CPACK_RPM_PACKAGE_REQUIRES "\ + boost-filesystem >= 1.67.0, \ + boost-log >= 1.67.0, \ + boost-program-options >= 1.67.0, \ + boost-thread >= 1.67.0, \ + libcap >= 2.22, \ + libcurl >= 7.0, \ + libdrm >= 2.4.97, \ + libevdev >= 1.5.6, \ + libopusenc >= 0.2.1, \ + libxcb >= 1.13, \ + libXtst >= 1.2.3, \ + openssl >= 1.1, \ + pulseaudio-libs >= 10.0") + # This should automatically figure out dependencies, doesn't work with the current config + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) + endif() endif() include(CPack) diff --git a/DOCKER_README.md b/DOCKER_README.md index 222cd163f02..71338e0a612 100644 --- a/DOCKER_README.md +++ b/DOCKER_README.md @@ -71,13 +71,13 @@ port `47990` (e.g. `http://:47990`). The internal port must be `47990`, (e.g. `-p 8080:47990`). All the ports listed in the `docker run` and `docker-compose` examples are required. -| Parameter | Function | Example Value | Required | -|-----------------------------|---------------------------|--------------------|----------| -| `-p :47990` | Web UI Port | `47990` | True | -| `-v :/config` | Volume mapping | `/home/sunshine` | True | -| `-e PUID=` | User ID | `1001` | False | -| `-e PGID=` | Group ID | `1001` | False | -| `-e TZ=` | Lookup TZ value [here][1] | `America/New_York` | False | +| Parameter | Function | Example Value | Required | +|-----------------------------|----------------------|--------------------|----------| +| `-p :47990` | Web UI Port | `47990` | True | +| `-v :/config` | Volume mapping | `/home/sunshine` | True | +| `-e PUID=` | User ID | `1001` | False | +| `-e PGID=` | Group ID | `1001` | False | +| `-e TZ=` | Lookup [TZ value][1] | `America/New_York` | False | [1]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones diff --git a/Dockerfile b/Dockerfile index 99c8795fb4b..9ff9d0d93e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN apt-get update -y \ libboost-filesystem-dev=1.74.0* \ libboost-log-dev=1.74.0* \ libboost-thread-dev=1.74.0* \ + libboost-program-options-dev=1.74.0* \ libcap-dev=1:2.44* \ libcurl4-openssl-dev=7.81.0* \ libdrm-dev=2.4.110* \ @@ -43,7 +44,6 @@ WORKDIR /root/sunshine-build/ COPY . . # setup npm and dependencies -WORKDIR /root/sunshine-build/src_assets/common/assets/web RUN npm install # setup build directory diff --git a/README.rst b/README.rst index f7853dee23a..7a7cf7f545f 100644 --- a/README.rst +++ b/README.rst @@ -4,34 +4,91 @@ LizardByte has the full documentation hosted on `Read the Docs `_. @@ -69,3 +126,7 @@ Stats .. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=AUR&style=for-the-badge&query=$.results.0.NumVotes&url=https%3A%2F%2Fapp.lizardbyte.dev%2Funo%2Faur%2Fsunshine.json&logo=archlinux :alt: AUR votes :target: https://aur.archlinux.org/packages/sunshine + +.. _nvenc support matrix: https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new +.. _obs-amd hardware support: https://github.com/obsproject/obs-amd-encoder/wiki/Hardware-Support +.. _VAAPI hardware support: https://www.intel.com/content/www/us/en/developer/articles/technical/linuxmedia-vaapi.html diff --git a/cmake/FindFFMPEG.cmake b/cmake/FindFFMPEG.cmake deleted file mode 100644 index 515d23ea327..00000000000 --- a/cmake/FindFFMPEG.cmake +++ /dev/null @@ -1,144 +0,0 @@ -# - Try to find FFMPEG -# Once done this will define -# FFMPEG_FOUND - System has FFMPEG -# FFMPEG_INCLUDE_DIRS - The FFMPEG include directories -# FFMPEG_LIBRARIES - The libraries needed to use FFMPEG -# FFMPEG_LIBRARY_DIRS - The directory to find FFMPEG libraries -# -# written by Roy Shilkrot 2013 http://www.morethantechnical.com/ -# - -find_package(PkgConfig) - - -MACRO(FFMPEG_FIND varname shortname headername) - - IF(NOT WIN32) - PKG_CHECK_MODULES(PC_${varname} ${shortname}) - - FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}" - HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS} - NO_DEFAULT_PATH - ) - ELSE() - FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}") - ENDIF() - - IF(${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") - message(STATUS "look for newer strcture") - IF(NOT WIN32) - PKG_CHECK_MODULES(PC_${varname} "lib${shortname}") - - FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}" - HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS} - NO_DEFAULT_PATH - ) - ELSE() - FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}") - IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") - #Desperate times call for desperate measures - MESSAGE(STATUS "globbing...") - FILE(GLOB_RECURSE ${varname}_INCLUDE_DIR "/ffmpeg*/${headername}") - MESSAGE(STATUS "found: ${${varname}_INCLUDE_DIR}") - IF(${varname}_INCLUDE_DIR) - GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH) - GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH) - ELSE() - SET(${varname}_INCLUDE_DIR "${varname}_INCLUDE_DIR-NOTFOUND") - ENDIF() - ENDIF() - ENDIF() - ENDIF() - - - IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") - MESSAGE(STATUS "Can't find includes for ${shortname}...") - ELSE() - MESSAGE(STATUS "Found ${shortname} include dirs: ${${varname}_INCLUDE_DIR}") - - #GET_DIRECTORY_PROPERTY(FFMPEG_PARENT DIRECTORY ${${varname}_INCLUDE_DIR} PARENT_DIRECTORY) - GET_FILENAME_COMPONENT(FFMPEG_PARENT ${${varname}_INCLUDE_DIR} PATH) - MESSAGE(STATUS "Using FFMpeg dir parent as hint: ${FFMPEG_PARENT}") - - IF(NOT WIN32) - FIND_LIBRARY(${varname}_LIBRARIES NAMES ${shortname} - HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT}) - ELSE() - FIND_PATH(${varname}_LIBRARIES "${shortname}.dll.a" HINTS ${FFMPEG_PARENT}) - # FILE(GLOB_RECURSE ${varname}_LIBRARIES "${FFMPEG_PARENT}/*${shortname}.lib") - # GLOBing is very bad... but windows sux, this is the only thing that works - ENDIF() - - IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND") - MESSAGE(STATUS "look for newer structure for library") - FIND_LIBRARY(${varname}_LIBRARIES NAMES lib${shortname} - HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT}) - ENDIF() - - - IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND") - MESSAGE(STATUS "Can't find lib for ${shortname}...") - ELSE() - MESSAGE(STATUS "Found ${shortname} libs: ${${varname}_LIBRARIES}") - ENDIF() - - - IF(NOT ${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND" - AND NOT ${varname}_LIBRARIES STREQUAL ${varname}_LIBRARIES-NOTFOUND) - - MESSAGE(STATUS "found ${shortname}: include ${${varname}_INCLUDE_DIR} lib ${${varname}_LIBRARIES}") - SET(FFMPEG_${varname}_FOUND 1) - SET(FFMPEG_${varname}_INCLUDE_DIRS ${${varname}_INCLUDE_DIR}) - SET(FFMPEG_${varname}_LIBS ${${varname}_LIBRARIES}) - ELSE() - MESSAGE(STATUS "Can't find ${shortname}") - ENDIF() - - ENDIF() - -ENDMACRO(FFMPEG_FIND) - -FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) -FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) -FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) -FFMPEG_FIND(LIBAVUTIL avutil avutil.h) -FFMPEG_FIND(LIBSWSCALE swscale swscale.h) - -SET(FFMPEG_FOUND "NO") -IF (FFMPEG_LIBAVFORMAT_FOUND AND - FFMPEG_LIBAVDEVICE_FOUND AND - FFMPEG_LIBAVCODEC_FOUND AND - FFMPEG_LIBAVUTIL_FOUND AND - FFMPEG_LIBSWSCALE_FOUND - ) - - - SET(FFMPEG_FOUND "YES") - - SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) - - SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) - - SET(FFMPEG_LIBRARIES - ${FFMPEG_LIBAVFORMAT_LIBS} - ${FFMPEG_LIBAVDEVICE_LIBS} - ${FFMPEG_LIBAVCODEC_LIBS} - ${FFMPEG_LIBAVUTIL_LIBS} - ${FFMPEG_LIBSWSCALE_LIBS} - ) - -ELSE () - - MESSAGE(STATUS "Could not find FFMPEG") - -ENDIF() - -message(STATUS ${FFMPEG_LIBRARIES} ${FFMPEG_LIBAVFORMAT_LIBRARIES}) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(FFMPEG DEFAULT_MSG - FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) - -mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARY_DIRS FFMPEG_LIBRARIES) diff --git a/cmake/FindLIBDRM.cmake b/cmake/FindLIBDRM.cmake index fd0548c1a1e..6e050018460 100644 --- a/cmake/FindLIBDRM.cmake +++ b/cmake/FindLIBDRM.cmake @@ -18,4 +18,4 @@ find_library(LIBDRM_LIBRARIES NAMES libdrm.so PATHS ${PC_LIBDRM_LIBDIR} ${PC_LIB mark_as_advanced(LIBDRM_INCLUDE_DIRS LIBDRM_LIBRARIES) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LIBDRM REQUIRED_VARS LIBDRM_LIBRARIES LIBDRM_INCLUDE_DIRS) \ No newline at end of file +find_package_handle_standard_args(LIBDRM REQUIRED_VARS LIBDRM_LIBRARIES LIBDRM_INCLUDE_DIRS) diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake index 377f0545cda..cf66d83abaf 100644 --- a/cmake/FindWayland.cmake +++ b/cmake/FindWayland.cmake @@ -22,57 +22,59 @@ IF (NOT WIN32) - # Use pkg-config to get the directories and then use these values - # in the find_path() and find_library() calls - find_package(PkgConfig) - PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor) + # Use pkg-config to get the directories and then use these values + # in the find_path() and find_library() calls + find_package(PkgConfig) + PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor) - set(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) + set(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) - find_path(WAYLAND_CLIENT_INCLUDE_DIRS NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - find_library(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - if(WAYLAND_CLIENT_INCLUDE_DIRS AND WAYLAND_CLIENT_LIBRARIES) - set(Wayland_Client_FOUND TRUE) - else() - set(Wayland_Client_FOUND FALSE) - endif() - mark_as_advanced(WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES) + find_path(WAYLAND_CLIENT_INCLUDE_DIRS NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + find_library(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + if(WAYLAND_CLIENT_INCLUDE_DIRS AND WAYLAND_CLIENT_LIBRARIES) + set(Wayland_Client_FOUND TRUE) # cmake-lint: disable=C0103 + else() + set(Wayland_Client_FOUND FALSE) # cmake-lint: disable=C0103 + endif() + mark_as_advanced(WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES) - find_path(WAYLAND_CURSOR_INCLUDE_DIRS NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - find_library(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - if(WAYLAND_CURSOR_INCLUDE_DIRS AND WAYLAND_CURSOR_LIBRARIES) - set(Wayland_Cursor_FOUND TRUE) - else() - set(Wayland_Cursor_FOUND FALSE) - endif() - mark_as_advanced(WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES) + find_path(WAYLAND_CURSOR_INCLUDE_DIRS NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + find_library(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + if(WAYLAND_CURSOR_INCLUDE_DIRS AND WAYLAND_CURSOR_LIBRARIES) + set(Wayland_Cursor_FOUND TRUE) # cmake-lint: disable=C0103 + else() + set(Wayland_Cursor_FOUND FALSE) # cmake-lint: disable=C0103 + endif() + mark_as_advanced(WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES) - find_path(WAYLAND_EGL_INCLUDE_DIRS NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - find_library(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - if(WAYLAND_EGL_INCLUDE_DIRS AND WAYLAND_EGL_LIBRARIES) - set(Wayland_EGL_FOUND TRUE) - else() - set(Wayland_EGL_FOUND FALSE) - endif() - mark_as_advanced(WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES) + find_path(WAYLAND_EGL_INCLUDE_DIRS NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + find_library(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + if(WAYLAND_EGL_INCLUDE_DIRS AND WAYLAND_EGL_LIBRARIES) + set(Wayland_EGL_FOUND TRUE) # cmake-lint: disable=C0103 + else() + set(Wayland_EGL_FOUND FALSE) # cmake-lint: disable=C0103 + endif() + mark_as_advanced(WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES) - find_path(WAYLAND_SERVER_INCLUDE_DIRS NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - find_library(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - if(WAYLAND_SERVER_INCLUDE_DIRS AND WAYLAND_SERVER_LIBRARIES) - set(Wayland_Server_FOUND TRUE) - else() - set(Wayland_Server_FOUND FALSE) - endif() - mark_as_advanced(WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES) + find_path(WAYLAND_SERVER_INCLUDE_DIRS NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + find_library(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + if(WAYLAND_SERVER_INCLUDE_DIRS AND WAYLAND_SERVER_LIBRARIES) + set(Wayland_Server_FOUND TRUE) # cmake-lint: disable=C0103 + else() + set(Wayland_Server_FOUND FALSE) # cmake-lint: disable=C0103 + endif() + mark_as_advanced(WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES) - set(WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS} ${WAYLAND_SERVER_INCLUDE_DIRS} ${WAYLAND_EGL_INCLUDE_DIRS} ${WAYLAND_CURSOR_INCLUDE_DIRS}) - set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES}) - mark_as_advanced(WAYLAND_INCLUDE_DIRS WAYLAND_LIBRARIES) + set(WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS} ${WAYLAND_SERVER_INCLUDE_DIRS} + ${WAYLAND_EGL_INCLUDE_DIRS} ${WAYLAND_CURSOR_INCLUDE_DIRS}) + set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} + ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES}) + mark_as_advanced(WAYLAND_INCLUDE_DIRS WAYLAND_LIBRARIES) - list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIRS) + list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIRS) - include(FindPackageHandleStandardArgs) + include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Wayland REQUIRED_VARS WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIRS HANDLE_COMPONENTS) + find_package_handle_standard_args(Wayland REQUIRED_VARS WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIRS HANDLE_COMPONENTS) ENDIF () diff --git a/docs/requirements.txt b/docs/requirements.txt index 79ce1cac540..82012203a23 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ furo==2022.12.7 m2r2==0.3.3 -Sphinx==5.3.0 +Sphinx==6.1.1 sphinx-copybutton==0.5.1 diff --git a/docs/source/about/advanced_usage.rst b/docs/source/about/advanced_usage.rst index 2ab43a856c6..03e46983dcf 100644 --- a/docs/source/about/advanced_usage.rst +++ b/docs/source/about/advanced_usage.rst @@ -2,6 +2,18 @@ Advanced Usage ============== Sunshine will work with the default settings for most users. In some cases you may want to configure Sunshine further. +Performance Tips +---------------- + +AMD +^^^ +In Windows, enabling `Enahanced Sync` in AMD's settings may help reduce the latency by an additional frame. This +applies to `amfenc` and `libx264`. + +Nvidia +^^^^^^ +Enabling `Fast Sync` in Nvidia settings may help reduce latency. + Configuration ------------- The default location for the configuration file is listed below. You can use another location if you @@ -21,7 +33,7 @@ location by modifying the configuration file. Docker /config/ Linux ~/.config/sunshine/ macOS ~/.config/sunshine/ - Windows ./config/ + Windows %ProgramFiles%\\Sunshine\\config ========= =========== **Example** @@ -81,6 +93,20 @@ min_log_level min_log_level = info +log_path +^^^^^^^^ + +**Description** + The path where the sunshine log is stored. + +**Default** + ``sunshine.log`` + +**Example** + .. code-block:: text + + log_path = sunshine.log + Controls -------- @@ -341,6 +367,9 @@ dwmflush If enabled, this feature will automatically deactivate if the client framerate exceeds the host monitor's current refresh rate. + .. Note:: If you disable this option, you may see video stuttering during mouse movement in certain scenarios. + It is recommended to leave enabled when possible. + **Default** ``enabled`` @@ -638,7 +667,7 @@ qp ^^ **Description** - Quantitization Parameter. Some devices don't support Constant Bit Rate. For those devices, QP is used instead. + Quantization Parameter. Some devices don't support Constant Bit Rate. For those devices, QP is used instead. .. Warning:: Higher value means more compression, but less quality. @@ -654,7 +683,7 @@ min_threads ^^^^^^^^^^^ **Description** - Minimum number of threads used by ffmpeg to encode the video. + Minimum number of threads used for software encoding. .. Note:: Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest value that can reliably encode at your @@ -824,27 +853,52 @@ nv_preset ========== =========== Value Description ========== =========== - default let ffmpeg decide - hp high performance + p1 fastest (lowest quality) + p2 faster (lower quality) + p3 fast (low quality) + p4 medium (default) + p5 slow (good quality) + p6 slower (better quality) + p7 slowest (best quality) + ========== =========== + +**Default** + ``p4`` + +**Example** + .. code-block:: text + + nv_preset = p4 + +nv_tune +^^^^^^^ + +**Description** + The encoder tuning profile. + + .. Note:: This option only applies when using nvenc `encoder`_. + +**Choices** + +.. table:: + :widths: auto + + ========== =========== + Value Description + ========== =========== hq high quality - slow high quality, 2 passes - medium high quality, 1 pass - fast high performance, 1 pass - bd ll low latency - llhq low latency, high quality - llhp low latency, high performance + ull ultra low latency lossless lossless - losslesshp lossless, high performance ========== =========== **Default** - ``llhq`` + ``ull`` **Example** .. code-block:: text - nv_preset = llhq + nv_tune = ull nv_rc ^^^^^ @@ -854,8 +908,6 @@ nv_rc .. Note:: This option only applies when using nvenc `encoder`_. - .. Note:: Moonlight does not currently support variable bitrate, although it can still be selected here. - **Choices** .. table:: @@ -864,22 +916,18 @@ nv_rc ========== =========== Value Description ========== =========== - auto let ffmpeg decide constqp constant QP mode - cbr constant bitrate - cbr_hq constant bitrate, high quality - cbr_ld_hq constant bitrate, low delay, high quality vbr variable bitrate - vbr_hq variable bitrate, high quality + cbr constant bitrate ========== =========== **Default** - ``auto`` + ``cbr`` **Example** .. code-block:: text - nv_rc = auto + nv_rc = cbr nv_coder ^^^^^^^^ @@ -887,7 +935,7 @@ nv_coder **Description** The entropy encoding to use. - .. Note:: This option only applies when using nvenc `encoder`_. + .. Note:: This option only applies when using H264 with nvenc `encoder`_. **Choices** @@ -898,8 +946,8 @@ nv_coder Value Description ========== =========== auto let ffmpeg decide - cabac - cavlc + cabac context adaptive binary arithmetic coding - higher quality + cavlc context adaptive variable-length coding - faster decode ========== =========== **Default** @@ -926,9 +974,9 @@ amd_quality ========== =========== Value Description ========== =========== - default let ffmpeg decide - speed fast - balanced balance performance and speed + speed prefer speed + balanced balanced + quality prefer quality ========== =========== **Default** @@ -947,8 +995,6 @@ amd_rc .. Note:: This option only applies when using amdvce `encoder`_. - .. Note:: Moonlight does not currently support variable bitrate, although it can still be selected here. - **Choices** .. table:: @@ -957,20 +1003,19 @@ amd_rc =========== =========== Value Description =========== =========== - auto let ffmpeg decide - constqp constant QP mode + cqp constant qp mode cbr constant bitrate vbr_latency variable bitrate, latency constrained vbr_peak variable bitrate, peak constrained =========== =========== **Default** - ``auto`` + ``vbr_latency`` **Example** .. code-block:: text - amd_rc = auto + amd_rc = vbr_latency amd_coder ^^^^^^^^^ @@ -978,7 +1023,7 @@ amd_coder **Description** The entropy encoding to use. - .. Note:: This option only applies when using nvenc `encoder`_. + .. Note:: This option only applies when using H264 with amdvce `encoder`_. **Choices** @@ -989,8 +1034,8 @@ amd_coder Value Description ========== =========== auto let ffmpeg decide - cabac - cavlc + cabac context adaptive variable-length coding - higher quality + cavlc context adaptive binary arithmetic coding - faster decode ========== =========== **Default** diff --git a/docs/source/about/installation.rst b/docs/source/about/installation.rst index 5e51f716659..aa64a189a7f 100644 --- a/docs/source/about/installation.rst +++ b/docs/source/about/installation.rst @@ -21,19 +21,10 @@ See :ref:`Docker ` for additional information. Linux ----- -First, follow the instructions for your preferred package type below. - -Then start sunshine with the following command, unless a start command is listed in the specified package. - -.. code-block:: bash - - sunshine +Follow the instructions for your preferred package type below. AppImage ^^^^^^^^ -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:appimage?logo=github&style=for-the-badge - :alt: GitHub issues by-label - According to AppImageLint the supported distro matrix of the AppImage is below. - [✖] Debian oldstable (buster) @@ -82,9 +73,6 @@ Uninstall: Debian Package ^^^^^^^^^^^^^^ -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:deb?logo=github&style=for-the-badge - :alt: GitHub issues by-label - #. Download ``sunshine-{ubuntu-version}.deb`` and run the following code. .. code-block:: bash @@ -103,9 +91,6 @@ Uninstall: Flatpak Package ^^^^^^^^^^^^^^^ -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:flatpak?logo=github&style=for-the-badge - :alt: GitHub issues by-label - #. Install `Flatpak `_ as required. #. Download ``sunshine_{arch}.flatpak`` and run the following code. @@ -145,9 +130,6 @@ Uninstall: RPM Package ^^^^^^^^^^^ -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:rpm?logo=github&style=for-the-badge - :alt: GitHub issues by-label - #. Add `rpmfusion` repositories by running the following code. .. code-block:: bash @@ -170,12 +152,11 @@ Uninstall: macOS ----- -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:macos?logo=github&style=for-the-badge - :alt: GitHub issues by-label +Sunshine on macOS is experimental. Gamepads do not work. Other features may not work as expected. pkg ^^^ -.. Warning:: The `pkg` does not include runtime dependencies and should be considered experimental. +.. Warning:: The `pkg` does not include runtime dependencies. #. Download the ``sunshine.pkg`` file and install it as normal. @@ -218,16 +199,14 @@ Uninstall: Windows ------- -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:windows:10?logo=github&style=for-the-badge - :alt: GitHub issues by-label - -.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:windows:11?logo=github&style=for-the-badge - :alt: GitHub issues by-label Installer ^^^^^^^^^ #. Download and install ``sunshine-windows.exe`` +.. Attention:: You should carefully select or unselect the options you want to install. Do not blindly install or enable + features. + To uninstall, find Sunshine in the list `here `_ and select "Uninstall" from the overflow menu. Different versions of Windows may provide slightly different steps for uninstall. diff --git a/docs/source/about/third_party_packages.rst b/docs/source/about/third_party_packages.rst index ad8979dc246..40a6bc70771 100644 --- a/docs/source/about/third_party_packages.rst +++ b/docs/source/about/third_party_packages.rst @@ -52,6 +52,3 @@ Legacy GitHub Repo .. image:: https://img.shields.io/github/release-date/loki-47-6F-64/sunshine?style=for-the-badge&logo=github :alt: GitHub Release Date - -.. image:: https://img.shields.io/github/downloads/loki-47-6F-64/sunshine/total?style=for-the-badge&logo=github - :alt: GitHub Releases diff --git a/docs/source/about/usage.rst b/docs/source/about/usage.rst index 7d59b715122..f6c574f12fe 100644 --- a/docs/source/about/usage.rst +++ b/docs/source/about/usage.rst @@ -1,23 +1,35 @@ Usage ===== #. See the `setup`_ section for your specific OS. -#. Run ``sunshine /sunshine.conf``. +#. If you did not install the service, then start sunshine with the following command, unless a start command is listed + in the specified package :ref:`installation ` instructions. - .. Note:: You do not need to specify a config file. If no config file is entered the default location will be used. + .. Note:: A service is a process that runs in the background. Running multiple instances of Sunshine is not + advised. - .. Attention:: The configuration file specified will be created if it doesn't exist. + **Basic usage** + .. code-block:: bash + + sunshine + + **Specify config file** + .. code-block:: bash + + sunshine /sunshine.conf + + .. Note:: You do not need to specify a config file. If no config file is entered the default location will be used. - .. Tip:: If using the Linux AppImage, replace ``sunshine`` with ``./sunshine.AppImage`` + .. Attention:: The configuration file specified will be created if it doesn't exist. #. Configure Sunshine in the web ui The web ui is available on `https://localhost:47990 `_ by default. You may replace `localhost` with your internal ip address. - .. Attention:: Ignore any warning given by your browser about "insecure website". + .. Attention:: Ignore any warning given by your browser about "insecure website". This is due to the SSL certificate + being self signed. - .. Caution:: If running for the first time, make sure to note the username and password Sunshine showed to you, - since you cannot get back later! + .. Caution:: If running for the first time, make sure to note the username and password that you created. **Add games and applications.** This can be configured in the web ui. @@ -26,8 +38,6 @@ Usage list of applications that are started just before running a stream. This is the directory within the GitHub repo. - .. Attention:: Application list is not fully supported on macOS - #. In Moonlight, you may need to add the PC manually. #. When Moonlight request you insert the correct pin on sunshine: @@ -76,7 +86,7 @@ Sunshine needs access to `uinput` to create mouse and gamepad events. .. code-block:: [Unit] - Description=Sunshine Gamestream Server for Moonlight + Description=Sunshine self-hosted game stream host for Moonlight. [Service] ExecStart= @@ -118,7 +128,7 @@ Sunshine needs access to `uinput` to create mouse and gamepad events. sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine)) - **Disable** + **Disable (for Xorg/X11)** .. code-block:: bash sudo setcap -r $(readlink -f $(which sunshine)) @@ -149,6 +159,32 @@ Windows ^^^^^^^ For gamepad support, install `ViGEmBus `_ +Sunshine firewall + **Add rule** + .. code-block:: batch + + cd /d "C:\Program Files\Sunshine\scripts" + add-firewall-rule.bat + + **Remove rule** + .. code-block:: batch + + cd /d "C:\Program Files\Sunshine\scripts" + remove-firewall-rule.bat + +Sunshine service + **Enable** + .. code-block:: batch + + cd /d "C:\Program Files\Sunshine\scripts" + install-service.bat + + **Disable** + .. code-block:: batch + + cd /d "C:\Program Files\Sunshine\scripts" + uninstall-service.bat + Shortcuts --------- All shortcuts start with ``CTRL + ALT + SHIFT``, just like Moonlight @@ -159,34 +195,43 @@ All shortcuts start with ``CTRL + ALT + SHIFT``, just like Moonlight Application List ---------------- - Applications should be configured via the web UI. -- A basic understanding of working directories and commands is recommended. +- A basic understanding of working directories and commands is required. - You can use Environment variables in place of values - ``$(HOME)`` will be replaced by the value of ``$HOME`` - ``$$`` will be replaced by ``$``, e.g. ``$$(HOME)`` will be become ``$(HOME)`` - ``env`` - Adds or overwrites Environment variables for the commands/applications run by Sunshine - ``"Variable name":"Variable value"`` - ``apps`` - The list of applications +- Advanced users may want to edit the application list manually. The format is ``json``. - Example application: .. code-block:: json { - "name":"An App", - "cmd":"command to open app", - "prep-cmd":[ - { - "do":"some-command", - "undo":"undo-that-command" - } - ], - "detached":[ - "some-command", - "another-command" - ] + "cmd": "command to open app", + "detached": [ + "some-command", + "another-command" + ], + "image-path": "/full-path/to/png-image", + "name": "An App", + "output": "/full-path/to/command-log-file", + "prep-cmd": [ + { + "do": "some-command", + "undo": "undo-that-command" + } + ], + "working-dir": "/full-path/to/working-directory" } + - ``cmd`` - The main application + - ``detached`` - A list of commands to be run and forgotten about + + - If not specified, a process is started that sleeps indefinitely + + - ``image-path`` - The full path to the cover art image to use. - ``name`` - The name of the application/game - ``output`` - The file where the output of the command is stored - - ``detached`` - A list of commands to be run and forgotten about - ``prep-cmd`` - A list of commands to be run before/after the application - If any of the prep-commands fail, starting the application is aborted @@ -196,12 +241,9 @@ Application List - ``undo`` - Run after the application has terminated - - This should not fail considering it is supposed to undo the ``do`` commands - - If it fails, Sunshine is terminated - - - ``cmd`` - The main application + - Failures of ``undo`` commands are ignored - - If not specified, a process is started that sleeps indefinitely + - ``working-dir`` - The working directory to use. If not specified, Sunshine will use the application directory. Considerations -------------- @@ -214,3 +256,11 @@ Considerations - In addition to the apps listed, one app "Desktop" is hardcoded into Sunshine. It does not start an application, instead it simply starts a stream. - For the Linux flatpak you must prepend commands with ``flatpak-spawn --host``. + +Tutorials +--------- +Tutorial videos are available `here `_. + +.. admonition:: Community! + + Tutorials are community generated. Want to contribute? Reach out to us on our discord server. diff --git a/docs/source/building/linux.rst b/docs/source/building/linux.rst index 177c6ead32d..2ccdd7c025b 100644 --- a/docs/source/building/linux.rst +++ b/docs/source/building/linux.rst @@ -18,6 +18,7 @@ Install Requirements libboost-filesystem-dev \ libboost-log-dev \ libboost-thread-dev \ + libboost-program-options-dev \ libcap-dev \ # KMS libdrm-dev \ # KMS libevdev-dev \ @@ -40,7 +41,7 @@ Install Requirements nvidia-cuda-dev \ # Cuda, NvFBC nvidia-cuda-toolkit # Cuda, NvFBC -Fedora 35 +Fedora 36 ^^^^^^^^^ End of Life: TBD @@ -79,72 +80,6 @@ Install Requirements pulseaudio-libs-devel \ rpm-build # if you want to build an RPM binary package -Ubuntu 18.04 -^^^^^^^^^^^^ -End of Life: April 2028 - -Install Repositories - .. code-block:: bash - - sudo apt update && sudo apt install \ - software-properties-common \ - && add-apt-repository ppa:savoury1/boost-defaults-1.71 && \ - add-apt-repository ppa:ubuntu-toolchain-r/test && \ - -Install Requirements - .. code-block:: bash - - sudo apt install \ - build-essential \ - cmake \ - gcc-10 \ - g++-10 \ - libavdevice-dev \ - libboost-filesystem1.71-dev \ - libboost-log1.71-dev \ - libboost-regex1.71-dev \ - libboost-thread1.71-dev \ - libcap-dev \ # KMS - libdrm-dev \ # KMS - libevdev-dev \ - libnuma-dev \ - libopus-dev \ - libpulse-dev \ - libssl-dev \ - libva-dev \ - libvdpau-dev \ - libwayland-dev \ # Wayland - libx11-dev \ # X11 - libxcb-shm0-dev \ # X11 - libxcb-xfixes0-dev \ # X11 - libxcb1-dev \ # X11 - libxfixes-dev \ # X11 - libxrandr-dev \ # X11 - libxtst-dev \ # X11 - nodejs \ - npm \ - wget - -Update gcc alias - .. code-block:: bash - - update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10 - -Install CuDA - .. code-block:: bash - - wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run --progress=bar:force:noscroll -q --show-progress -O ./cuda.run && chmod a+x ./cuda.run - ./cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm && rm ./cuda.run - -Install CMake - .. code-block:: bash - - wget https://cmake.org/files/v3.22/cmake-3.22.2-linux-x86_64.sh - mkdir /opt/cmake - sh /cmake-3.22.2-linux-x86_64.sh --prefix=/opt/cmake --skip-license - ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake - cmake --version - Ubuntu 20.04 ^^^^^^^^^^^^ End of Life: April 2030 @@ -160,6 +95,7 @@ Install Requirements libboost-filesystem-dev \ libboost-log-dev \ libboost-thread-dev \ + libboost-program-options-dev \ libcap-dev \ # KMS libdrm-dev \ # KMS libevdev-dev \ @@ -206,6 +142,7 @@ Install Requirements libboost-filesystem-dev \ libboost-log-dev \ libboost-thread-dev \ + libboost-program-options-dev \ libcap-dev \ # KMS libdrm-dev \ # KMS libevdev-dev \ @@ -231,27 +168,16 @@ npm dependencies Install npm dependencies. .. code-block:: bash - pushd ./src_assets/common/assets/web npm install - popd Build ----- .. Attention:: Ensure you are in the build directory created during the clone step earlier before continuing. -Debian based OSes - .. code-block:: bash - - cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 .. - -Red Hat based OSes - .. code-block:: bash - - cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ .. +.. code-block:: bash -Finally - .. code-block:: bash + cmake .. + make -j ${nproc} - make -j ${nproc} - cpack -G DEB # optionally, create a deb package - cpack -G RPM # optionally, create a rpm package + cpack -G DEB # optionally, create a deb package + cpack -G RPM # optionally, create a rpm package diff --git a/docs/source/building/macos.rst b/docs/source/building/macos.rst index 447a0fd6702..5ff3e74e980 100644 --- a/docs/source/building/macos.rst +++ b/docs/source/building/macos.rst @@ -12,7 +12,7 @@ MacPorts Install Requirements .. code-block:: bash - sudo port install boost cmake libopus npm9 + sudo port install avahi boost180 cmake curl libopus npm9 pkgconfig Homebrew """""""" @@ -29,9 +29,7 @@ npm dependencies Install npm dependencies. .. code-block:: bash - pushd ./src_assets/common/assets/web npm install - popd Build ----- @@ -45,5 +43,4 @@ Build cpack -G DragNDrop # optionally, create a macOS dmg package If cmake fails complaining to find Boost, try to set the path explicitly. - ``cmake -DBOOST_ROOT=[boost path] ..``, e.g., ``cmake -DBOOST_ROOT=/opt/local/libexec/boost/1.76 ..`` - + ``cmake -DBOOST_ROOT=[boost path] ..``, e.g., ``cmake -DBOOST_ROOT=/opt/local/libexec/boost/1.80 ..`` diff --git a/docs/source/building/windows.rst b/docs/source/building/windows.rst index c42ebc52895..82b0dfe6c3d 100644 --- a/docs/source/building/windows.rst +++ b/docs/source/building/windows.rst @@ -3,14 +3,20 @@ Windows Requirements ------------ -First you need to install `MSYS2 `_, then startup "MSYS2 MinGW 64-bit" and install the -following packages using: +First you need to install `MSYS2 `_, then startup "MSYS2 MinGW 64-bit" and execute the following +codes. -.. code-block:: bash +Update all packages: + .. code-block:: bash + + pacman -Suy - pacman -S mingw-w64-x86_64-binutils mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake \ - mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost \ - git mingw-w64-x86_64-make cmake make gcc +Install dependencies: + .. code-block:: bash + + pacman -S base-devel cmake diffutils gcc git make mingw-w64-x86_64-binutils \ + mingw-w64-x86_64-boost mingw-w64-x86_64-cmake mingw-w64-x86_64-curl \ + mingw-w64-x86_64-openssl mingw-w64-x86_64-opus mingw-w64-x86_64-toolchain npm dependencies ---------------- @@ -19,9 +25,7 @@ Install nodejs and npm. Downloads available `here `_ project if you're interested in an automated +migration option. At the time of writing this GSMS offers the ability to migrate your custom games and apps. The +working directory, command, and image are all set in Sunshine's ``apps.json`` file. The box-art image is also copied +to a specified directory. + +Limitations +----------- +Sunshine does have some limitations, as compared to Nvidia GameStream. + +- HDR support is limited and currently HDR is converted to SDR. +- Automatic game/application list. +- Changing game settings automatically, to optimize streaming. diff --git a/docs/source/legal/legal.rst b/docs/source/legal/legal.rst new file mode 100644 index 00000000000..13bc3660140 --- /dev/null +++ b/docs/source/legal/legal.rst @@ -0,0 +1,21 @@ +Legal +===== +.. Attention:: This documentation is for informational purposes only and is not intended as legal advice. If you have + any legal questions or concerns about using Sunshine, we recommend consulting with a lawyer. + +Sunshine is licensed under the GPL-3.0 license, which allows for free use and modification of the software. +The full text of the license can be reviewed `here `_. + +Commercial Use +-------------- +Sunshine can be used in commercial applications without any limitations. This means that businesses and organizations +can use Sunshine to create and sell products or services without needing to seek permission or pay a fee. + +However, it is important to note that the GPL-3.0 license does not grant any rights to distribute or sell the encoders +contained within Sunshine. If you plan to sell access to Sunshine as part of their distribution, you are responsible +for obtaining the necessary licenses to do so. This may include obtaining a license from the +Motion Picture Experts Group (MPEG-LA) and/or any other necessary licensing requirements. + +In summary, while Sunshine is free to use, it is the user's responsibility to ensure compliance with all applicable +licensing requirements when redistributing the software as part of a commercial offering. If you have any questions or +concerns about using Sunshine in a commercial setting, we recommend consulting with a lawyer. diff --git a/docs/source/toc.rst b/docs/source/toc.rst index efafa92bff1..eff935bb890 100644 --- a/docs/source/toc.rst +++ b/docs/source/toc.rst @@ -9,6 +9,12 @@ about/usage about/advanced_usage +.. toctree:: + :maxdepth: 2 + :caption: GameStream + + gamestream/gamestream + .. toctree:: :maxdepth: 2 :caption: Troubleshooting @@ -34,3 +40,9 @@ contributing/contributing contributing/localization contributing/testing + +.. toctree:: + :maxdepth: 2 + :caption: Legal + + legal/legal diff --git a/docs/source/troubleshooting/general.rst b/docs/source/troubleshooting/general.rst index 2bbb93c9f44..3b6d6aad241 100644 --- a/docs/source/troubleshooting/general.rst +++ b/docs/source/troubleshooting/general.rst @@ -1,13 +1,20 @@ General ======= + +Forgotten Credentials +--------------------- If you forgot your credentials to the web UI, try this. .. code-block:: bash sunshine --creds +Web UI Access +------------- Can't access the web UI? #. Check firewall rules. +Nvidia issues +------------- NvFBC, NvENC, or general issues with Nvidia graphics card. - Consumer grade Nvidia cards are software limited to a specific number of encodes. See `Video Encode and Decode GPU Support Matrix `_ diff --git a/docs/source/troubleshooting/linux.rst b/docs/source/troubleshooting/linux.rst index 0c8e3f979ba..5c2d7c8a37c 100644 --- a/docs/source/troubleshooting/linux.rst +++ b/docs/source/troubleshooting/linux.rst @@ -1,5 +1,8 @@ Linux ===== + +KMS Streaming fails +------------------- If screencasting fails with KMS, you may need to run the following to force unprivileged screencasting. .. code-block:: bash diff --git a/docs/source/troubleshooting/macos.rst b/docs/source/troubleshooting/macos.rst index 70a0d60c22f..551f6945f4a 100644 --- a/docs/source/troubleshooting/macos.rst +++ b/docs/source/troubleshooting/macos.rst @@ -1,5 +1,8 @@ macOS ===== + +Dynamic session lookup failed +----------------------------- If you get this error: `Dynamic session lookup supported but failed: launchd did not provide a socket path, verify that org.freedesktop.dbus-session.plist is loaded!` diff --git a/docs/source/troubleshooting/windows.rst b/docs/source/troubleshooting/windows.rst index 15053519cb1..31a1a6bafbe 100644 --- a/docs/source/troubleshooting/windows.rst +++ b/docs/source/troubleshooting/windows.rst @@ -1,4 +1,6 @@ Windows ======= -No gamepad is detected. - #. Verify that you've installed `ViGEmBus `_. + +No gamepad detected +------------------- +#. Verify that you've installed `ViGEmBus `_. diff --git a/package.json b/package.json new file mode 100644 index 00000000000..a826e89f375 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "@fortawesome/fontawesome-free": "6.2.1", + "bootstrap": "5.2.3", + "vue": "2.6.12" + } +} diff --git a/packaging/linux/aur/PKGBUILD b/packaging/linux/aur/PKGBUILD index f51a068ba5f..f8dfbc19982 100644 --- a/packaging/linux/aur/PKGBUILD +++ b/packaging/linux/aur/PKGBUILD @@ -25,7 +25,7 @@ prepare() { } build() { - pushd "$pkgname/src_assets/common/assets/web" + pushd "$pkgname" npm install popd diff --git a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml index e4f0f66512c..a27e4e7a05e 100644 --- a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml +++ b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml @@ -33,7 +33,7 @@ modules: buildsystem: simple build-commands: - cd tools/build && bison -y -d -o src/engine/jamgram.cpp src/engine/jamgram.y - - ./bootstrap.sh --prefix=$FLATPAK_DEST --with-libraries=system,thread,log || cat bootstrap.log + - ./bootstrap.sh --prefix=$FLATPAK_DEST --with-libraries=system,thread,log,program_options || cat bootstrap.log - ./b2 install variant=release link=static,shared runtime-link=shared cxxflags="$CXXFLAGS" linkflags="$LDFLAGS" -j $FLATPAK_BUILDER_N_JOBS sources: @@ -142,7 +142,7 @@ modules: NPM_CONFIG_LOGLEVEL: info build-commands: # Install npm dependencies - - cd ${FLATPAK_BUILDER_BUILDDIR}/src_assets/common/assets/web && npm install + - cd ${FLATPAK_BUILDER_BUILDDIR} && npm install config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCMAKE_INSTALL_PREFIX=/app diff --git a/packaging/macos/Portfile b/packaging/macos/Portfile index 6cd0f685577..fb5fb13a8f0 100644 --- a/packaging/macos/Portfile +++ b/packaging/macos/Portfile @@ -56,7 +56,7 @@ platform darwin { } pre-build { - system -W ${worksrcpath}/src_assets/common/assets/web "npm install" + system -W ${worksrcpath} "npm install" } notes-append "Run @PROJECT_NAME@ by executing 'sunshine ', e.g. 'sunshine ~/sunshine.conf' " diff --git a/src/audio.cpp b/src/audio.cpp index c5b6a976de1..153da68649c 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -39,6 +39,15 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] { 1, 1, platf::speaker::map_stereo, + 96000, + }, + { + SAMPLE_RATE, + 2, + 1, + 1, + platf::speaker::map_stereo, + 512000, }, { SAMPLE_RATE, @@ -46,6 +55,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] { 4, 2, platf::speaker::map_surround51, + 256000, }, { SAMPLE_RATE, @@ -53,6 +63,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] { 6, 0, platf::speaker::map_surround51, + 1536000, }, { SAMPLE_RATE, @@ -60,6 +71,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] { 5, 3, platf::speaker::map_surround71, + 450000, }, { SAMPLE_RATE, @@ -67,6 +79,7 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] { 8, 0, platf::speaker::map_surround71, + 2048000, }, }; @@ -74,9 +87,10 @@ auto control_shared = safe::make_shared(start_audio_control, stop_a void encodeThread(sample_queue_t samples, config_t config, void *channel_data) { auto packets = mail::man->queue(mail::audio_packets); + auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])]; - // FIXME: Pick correct opus_stream_config_t based on config.channels - auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])]; + // Encoding takes place on this thread + platf::adjust_thread_priority(platf::thread_priority_e::high); opus_t opus { opus_multistream_encoder_create( stream->sampleRate, @@ -84,17 +98,15 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) { stream->streams, stream->coupledStreams, stream->mapping, - OPUS_APPLICATION_AUDIO, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, nullptr) }; - // For some reason, audio is crackling when the encoder is set to constant bitstream. - // We simulate a constant bitstream with OPUS_SET_BITRATE(OPUS_BITRATE_MAX) --> - // which tries to occupy as much space as possible in the packet - opus_multistream_encoder_ctl(opus.get(), OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + opus_multistream_encoder_ctl(opus.get(), OPUS_SET_BITRATE(stream->bitrate)); + opus_multistream_encoder_ctl(opus.get(), OPUS_SET_VBR(0)); auto frame_size = config.packetDuration * stream->sampleRate / 1000; while(auto sample = samples->pop()) { - buffer_t packet { 1400 }; // 1KB + buffer_t packet { 1400 }; int bytes = opus_multistream_encode(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size()); if(bytes < 0) { @@ -104,14 +116,6 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) { return; } - // Even with OPUS_SET_BITRATE(OPUS_BITRATE_MAX), silent packets are smaller than the rest - // Drop silent packets to ensure Moonlight won't complain - // A packet size of 128 seems a reasonable enough threshold - if(bytes < 128) { - BOOST_LOG(verbose) << "Dropped silent packet"sv; - continue; - } - packet.fake_resize(bytes); packets->raise(channel_data, std::move(packet)); } @@ -119,9 +123,7 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) { void capture(safe::mail_t mail, config_t config, void *channel_data) { auto shutdown_event = mail->event(mail::shutdown); - - // FIXME: Pick correct opus_stream_config_t based on config.channels - auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])]; + auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])]; auto ref = control_shared.ref(); if(!ref) { @@ -174,6 +176,9 @@ void capture(safe::mail_t mail, config_t config, void *channel_data) { } } + // Capture takes place on this thread + platf::adjust_thread_priority(platf::thread_priority_e::critical); + auto samples = std::make_shared(30); std::thread thread { encodeThread, samples, config, channel_data }; @@ -225,7 +230,7 @@ int map_stream(int channels, bool quality) { int shift = quality ? 1 : 0; switch(channels) { case 2: - return STEREO; + return STEREO + shift; case 6: return SURROUND51 + shift; case 8: diff --git a/src/audio.h b/src/audio.h index 67f3af13989..17d3ebb4218 100644 --- a/src/audio.h +++ b/src/audio.h @@ -6,6 +6,7 @@ namespace audio { enum stream_config_e : int { STEREO, + HIGH_STEREO, SURROUND51, HIGH_SURROUND51, SURROUND71, @@ -19,6 +20,7 @@ struct opus_stream_config_t { int streams; int coupledStreams; const std::uint8_t *mapping; + int bitrate; }; extern opus_stream_config_t stream_configs[MAX_STREAM_CONFIG]; diff --git a/src/cbs.cpp b/src/cbs.cpp index d50bd1951fb..6844d91aa57 100644 --- a/src/cbs.cpp +++ b/src/cbs.cpp @@ -1,7 +1,7 @@ extern "C" { #include #include -#include +#include #include #include } diff --git a/src/config.cpp b/src/config.cpp index b7f483ac6f3..5bc04159bb8 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -25,50 +25,71 @@ using namespace std::literals; namespace config { namespace nv { +#ifdef __APPLE__ +// values accurate as of 27/12/2022, but aren't strictly necessary for MacOS build +#define NV_ENC_TUNING_INFO_HIGH_QUALITY 1 +#define NV_ENC_TUNING_INFO_LOW_LATENCY 2 +#define NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY 3 +#define NV_ENC_TUNING_INFO_LOSSLESS 4 +#define NV_ENC_PARAMS_RC_CONSTQP 0x0 +#define NV_ENC_PARAMS_RC_VBR 0x1 +#define NV_ENC_PARAMS_RC_CBR 0x2 +#define NV_ENC_H264_ENTROPY_CODING_MODE_CABAC 1 +#define NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC 2 +#else +#include +#endif + enum preset_e : int { - _default = 0, - slow, - medium, - fast, - hp, - hq, - bd, - ll_default, - llhq, - llhp, - lossless_default, // lossless presets must be the last ones - lossless_hp, + p1 = 12, // PRESET_P1, // must be kept in sync with + p2, // PRESET_P2, + p3, // PRESET_P3, + p4, // PRESET_P4, + p5, // PRESET_P5, + p6, // PRESET_P6, + p7 // PRESET_P7 +}; + +enum tune_e : int { + hq = NV_ENC_TUNING_INFO_HIGH_QUALITY, + ll = NV_ENC_TUNING_INFO_LOW_LATENCY, + ull = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY, + lossless = NV_ENC_TUNING_INFO_LOSSLESS }; enum rc_e : int { - constqp = 0x0, /**< Constant QP mode */ - vbr = 0x1, /**< Variable bitrate mode */ - cbr = 0x2, /**< Constant bitrate mode */ - cbr_ld_hq = 0x8, /**< low-delay CBR, high quality */ - cbr_hq = 0x10, /**< CBR, high quality (slower) */ - vbr_hq = 0x20 /**< VBR, high quality (slower) */ + constqp = NV_ENC_PARAMS_RC_CONSTQP, /**< Constant QP mode */ + vbr = NV_ENC_PARAMS_RC_VBR, /**< Variable bitrate mode */ + cbr = NV_ENC_PARAMS_RC_CBR /**< Constant bitrate mode */ }; enum coder_e : int { _auto = 0, - cabac, - cavlc + cabac = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC, + cavlc = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC, }; std::optional preset_from_view(const std::string_view &preset) { #define _CONVERT_(x) \ if(preset == #x##sv) return x - _CONVERT_(slow); - _CONVERT_(medium); - _CONVERT_(fast); - _CONVERT_(hp); - _CONVERT_(bd); - _CONVERT_(ll_default); - _CONVERT_(llhq); - _CONVERT_(llhp); - _CONVERT_(lossless_default); - _CONVERT_(lossless_hp); - if(preset == "default"sv) return _default; + _CONVERT_(p1); + _CONVERT_(p2); + _CONVERT_(p3); + _CONVERT_(p4); + _CONVERT_(p5); + _CONVERT_(p6); + _CONVERT_(p7); +#undef _CONVERT_ + return std::nullopt; +} + +std::optional tune_from_view(const std::string_view &tune) { +#define _CONVERT_(x) \ + if(tune == #x##sv) return x + _CONVERT_(hq); + _CONVERT_(ll); + _CONVERT_(ull); + _CONVERT_(lossless); #undef _CONVERT_ return std::nullopt; } @@ -79,9 +100,6 @@ std::optional rc_from_view(const std::string_view &rc) { _CONVERT_(constqp); _CONVERT_(vbr); _CONVERT_(cbr); - _CONVERT_(cbr_hq); - _CONVERT_(vbr_hq); - _CONVERT_(cbr_ld_hq); #undef _CONVERT_ return std::nullopt; } @@ -96,57 +114,76 @@ int coder_from_view(const std::string_view &coder) { } // namespace nv namespace amd { -enum quality_e : int { - _default = 0, - speed, - balanced, +#ifdef __APPLE__ +// values accurate as of 27/12/2022, but aren't strictly necessary for MacOS build +#define AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED 10 +#define AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY 0 +#define AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED 5 +#define AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED 1 +#define AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY 2 +#define AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED 0 +#define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP 0 +#define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR 3 +#define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR 2 +#define AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR 1 +#define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP 0 +#define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR 1 +#define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR 2 +#define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR 3 +#define AMF_VIDEO_ENCODER_UNDEFINED 0 +#define AMF_VIDEO_ENCODER_CABAC 1 +#define AMF_VIDEO_ENCODER_CALV 2 +#else +#include +#include +#endif + +enum class quality_hevc_e : int { + speed = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, + quality = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY, + balanced = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED +}; + +enum class quality_h264_e : int { + speed = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED, + quality = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, + balanced = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }; enum class rc_hevc_e : int { - constqp, /**< Constant QP mode */ - vbr_latency, /**< Latency Constrained Variable Bitrate */ - vbr_peak, /**< Peak Constrained Variable Bitrate */ - cbr, /**< Constant bitrate mode */ + cqp = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP, + vbr_latency = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, + vbr_peak = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, + cbr = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }; enum class rc_h264_e : int { - constqp, /**< Constant QP mode */ - cbr, /**< Constant bitrate mode */ - vbr_peak, /**< Peak Constrained Variable Bitrate */ - vbr_latency, /**< Latency Constrained Variable Bitrate */ + cqp = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP, + vbr_latency = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, + vbr_peak = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR, + cbr = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }; enum coder_e : int { - _auto = 0, - cabac, - cavlc + _auto = AMF_VIDEO_ENCODER_UNDEFINED, + cabac = AMF_VIDEO_ENCODER_CABAC, + cavlc = AMF_VIDEO_ENCODER_CALV }; -std::optional quality_from_view(const std::string_view &quality) { +std::optional quality_from_view(const std::string_view &quality_type, int codec) { #define _CONVERT_(x) \ - if(quality == #x##sv) return x + if(quality_type == #x##sv) return codec == 0 ? (int)quality_hevc_e::x : (int)quality_h264_e::x + _CONVERT_(quality); _CONVERT_(speed); _CONVERT_(balanced); - if(quality == "default"sv) return _default; -#undef _CONVERT_ - return std::nullopt; -} - -std::optional rc_h264_from_view(const std::string_view &rc) { -#define _CONVERT_(x) \ - if(rc == #x##sv) return (int)rc_h264_e::x - _CONVERT_(constqp); - _CONVERT_(vbr_latency); - _CONVERT_(vbr_peak); - _CONVERT_(cbr); #undef _CONVERT_ return std::nullopt; } -std::optional rc_hevc_from_view(const std::string_view &rc) { +std::optional rc_from_view(const std::string_view &rc, int codec) { #define _CONVERT_(x) \ - if(rc == #x##sv) return (int)rc_hevc_e::x - _CONVERT_(constqp); + if(rc == #x##sv) return codec == 0 ? (int)rc_hevc_e::x : (int)rc_h264_e::x + _CONVERT_(cqp); _CONVERT_(vbr_latency); _CONVERT_(vbr_peak); _CONVERT_(cbr); @@ -211,16 +248,19 @@ video_t video { }, // software { - nv::llhq, - std::nullopt, - -1 }, // nv + nv::p4, // preset + nv::ull, // tune + nv::cbr, // rc + nv::_auto // coder + }, // nv { - amd::balanced, - std::nullopt, - std::nullopt, - -1 }, // amd - + (int)amd::quality_h264_e::balanced, // quality (h264) + (int)amd::quality_hevc_e::balanced, // quality (hevc) + (int)amd::rc_h264_e::vbr_latency, // rate control (h264) + (int)amd::rc_hevc_e::vbr_latency, // rate control (hevc) + (int)amd::coder_e::_auto, // coder + }, // amd { 0, 0, @@ -296,6 +336,7 @@ sunshine_t sunshine { platf::appdata().string() + "/sunshine.conf", // config file {}, // cmd args 47989, + platf::appdata().string() + "/sunshine.log", // log file }; bool endline(char ch) { @@ -716,17 +757,23 @@ void apply_config(std::unordered_map &&vars) { string_f(vars, "sw_preset", video.sw.preset); string_f(vars, "sw_tune", video.sw.tune); int_f(vars, "nv_preset", video.nv.preset, nv::preset_from_view); + int_f(vars, "nv_tune", video.nv.tune, nv::tune_from_view); int_f(vars, "nv_rc", video.nv.rc, nv::rc_from_view); int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view); - int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view); + std::string quality; + string_f(vars, "amd_quality", quality); + if(!quality.empty()) { + video.amd.quality_h264 = amd::quality_from_view(quality, 1); + video.amd.quality_hevc = amd::quality_from_view(quality, 0); + } std::string rc; string_f(vars, "amd_rc", rc); int_f(vars, "amd_coder", video.amd.coder, amd::coder_from_view); if(!rc.empty()) { - video.amd.rc_h264 = amd::rc_h264_from_view(rc); - video.amd.rc_hevc = amd::rc_hevc_from_view(rc); + video.amd.rc_h264 = amd::rc_from_view(rc, 1); + video.amd.rc_hevc = amd::rc_from_view(rc, 0); } int_f(vars, "vt_coder", video.vt.coder, vt::coder_from_view); @@ -742,7 +789,7 @@ void apply_config(std::unordered_map &&vars) { path_f(vars, "pkey", nvhttp.pkey); path_f(vars, "cert", nvhttp.cert); string_f(vars, "sunshine_name", nvhttp.sunshine_name); - + path_f(vars, "log_path", config::sunshine.log_file); path_f(vars, "file_state", nvhttp.file_state); // Must be run after "file_state" diff --git a/src/config.h b/src/config.h index 4ecb9f3261f..7b1c705ec90 100644 --- a/src/config.h +++ b/src/config.h @@ -23,12 +23,14 @@ struct video_t { struct { std::optional preset; + std::optional tune; std::optional rc; int coder; } nv; struct { - std::optional quality; + std::optional quality_h264; + std::optional quality_hevc; std::optional rc_h264; std::optional rc_hevc; int coder; @@ -120,6 +122,7 @@ struct sunshine_t { } cmd; std::uint16_t port; + std::string log_file; }; extern video_t video; diff --git a/src/confighttp.cpp b/src/confighttp.cpp index 6cf6b12348a..1276c5973f9 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -6,6 +6,7 @@ #include "process.h" #include +#include #include #include @@ -68,7 +69,7 @@ void print_req(const req_https_t &request) { } void send_unauthorized(resp_https_t response, req_https_t request) { - auto address = request->remote_endpoint_address(); + auto address = request->remote_endpoint().address().to_string(); BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv; const SimpleWeb::CaseInsensitiveMultimap headers { { "WWW-Authenticate", R"(Basic realm="Sunshine Gamestream Host", charset="UTF-8")" } @@ -77,7 +78,7 @@ void send_unauthorized(resp_https_t response, req_https_t request) { } void send_redirect(resp_https_t response, req_https_t request, const char *path) { - auto address = request->remote_endpoint_address(); + auto address = request->remote_endpoint().address().to_string(); BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv; const SimpleWeb::CaseInsensitiveMultimap headers { { "Location", path } @@ -86,7 +87,7 @@ void send_redirect(resp_https_t response, req_https_t request, const char *path) } bool authenticate(resp_https_t response, req_https_t request) { - auto address = request->remote_endpoint_address(); + auto address = request->remote_endpoint().address().to_string(); auto ip_type = net::from_address(address); if(ip_type > http::origin_web_ui_allowed) { @@ -274,6 +275,17 @@ void getApps(resp_https_t response, req_https_t request) { response->write(content); } +void getLogs(resp_https_t response, req_https_t request) { + if(!authenticate(response, request)) return; + + print_req(request); + + std::string content = read_file(config::sunshine.log_file.c_str()); + SimpleWeb::CaseInsensitiveMultimap headers; + headers.emplace("Content-Type", "text/plain"); + response->write(SimpleWeb::StatusCode::success_ok, content, headers); +} + void saveApp(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; @@ -468,6 +480,7 @@ void getConfig(resp_https_t response, req_https_t request) { outputTree.put("status", "true"); outputTree.put("platform", SUNSHINE_PLATFORM); + outputTree.put("restart_supported", platf::restart_supported()); auto vars = config::parse_config(read_file(config::sunshine.config_file.c_str())); @@ -511,6 +524,37 @@ void saveConfig(resp_https_t response, req_https_t request) { } } +void restart(resp_https_t response, req_https_t request) { + if(!authenticate(response, request)) return; + + print_req(request); + + std::stringstream ss; + std::stringstream configStream; + ss << request->content.rdbuf(); + pt::ptree outputTree; + auto g = util::fail_guard([&]() { + std::ostringstream data; + + pt::write_json(data, outputTree); + response->write(data.str()); + }); + + if(!platf::restart_supported()) { + outputTree.put("status", false); + outputTree.put("error", "Restart is not currently supported on this platform"); + return; + } + + if(!platf::restart()) { + outputTree.put("status", false); + outputTree.put("error", "Restart failed"); + return; + } + + outputTree.put("status", true); +} + void savePassword(resp_https_t response, req_https_t request) { if(!config::sunshine.username.empty() && !authenticate(response, request)) return; @@ -636,11 +680,8 @@ void start() { auto port_https = map_port(PORT_HTTPS); - auto ctx = std::make_shared(boost::asio::ssl::context::tls); - ctx->use_certificate_chain_file(config::nvhttp.cert); - ctx->use_private_key_file(config::nvhttp.pkey, boost::asio::ssl::context::pem); - https_server_t server { ctx, 0 }; - server.default_resource = not_found; + https_server_t server { config::nvhttp.cert, config::nvhttp.pkey }; + server.default_resource["GET"] = not_found; server.resource["^/$"]["GET"] = getIndexPage; server.resource["^/pin$"]["GET"] = getPinPage; server.resource["^/apps$"]["GET"] = getAppsPage; @@ -651,9 +692,11 @@ void start() { server.resource["^/troubleshooting$"]["GET"] = getTroubleshootingPage; server.resource["^/api/pin$"]["POST"] = savePin; server.resource["^/api/apps$"]["GET"] = getApps; + server.resource["^/api/logs$"]["GET"] = getLogs; server.resource["^/api/apps$"]["POST"] = saveApp; server.resource["^/api/config$"]["GET"] = getConfig; server.resource["^/api/config$"]["POST"] = saveConfig; + server.resource["^/api/restart$"]["POST"] = restart; server.resource["^/api/password$"]["POST"] = savePassword; server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp; server.resource["^/api/clients/unpair$"]["POST"] = unpairAll; @@ -666,19 +709,11 @@ void start() { server.config.address = "0.0.0.0"s; server.config.port = port_https; - try { - server.bind(); - BOOST_LOG(info) << "Configuration UI available at [https://localhost:"sv << port_https << "]"; - } - catch(boost::system::system_error &err) { - BOOST_LOG(fatal) << "Couldn't bind http server to ports ["sv << port_https << "]: "sv << err.what(); - - shutdown_event->raise(true); - return; - } auto accept_and_run = [&](auto *server) { try { - server->accept_and_run(); + server->start([](unsigned short port) { + BOOST_LOG(info) << "Configuration UI available at [https://localhost:"sv << port << "]"; + }); } catch(boost::system::system_error &err) { // It's possible the exception gets thrown after calling server->stop() from a different thread @@ -686,7 +721,7 @@ void start() { return; } - BOOST_LOG(fatal) << "Couldn't start Configuration HTTPS server to port ["sv << port_https << "]: "sv << err.what(); + BOOST_LOG(fatal) << "Couldn't start Configuration HTTPS server on port ["sv << port_https << "]: "sv << err.what(); shutdown_event->raise(true); return; } diff --git a/src/crypto.cpp b/src/crypto.cpp index 45b65abcff7..c0de077295a 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -4,8 +4,6 @@ #include namespace crypto { -using big_num_t = util::safe_ptr; -// using rsa_t = util::safe_ptr; using asn1_string_t = util::safe_ptr; cert_chain_t::cert_chain_t() : _certs {}, _cert_ctx { X509_STORE_CTX_new() } {} @@ -315,12 +313,7 @@ aes_t gen_aes_key(const std::array &salt, const std::string_view &p sha256_t hash(const std::string_view &plaintext) { sha256_t hsh; - - SHA256_CTX sha256; - SHA256_Init(&sha256); - SHA256_Update(&sha256, plaintext.data(), plaintext.size()); - SHA256_Final(hsh.data(), &sha256); - + EVP_Digest(plaintext.data(), plaintext.size(), hsh.data(), nullptr, EVP_sha256(), nullptr); return hsh; } @@ -409,17 +402,20 @@ std::vector sign(const pkey_t &pkey, const std::string_view &data, cons creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits) { x509_t x509 { X509_new() }; - pkey_t pkey { EVP_PKEY_new() }; + pkey_ctx_t ctx { EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) }; + pkey_t pkey; - big_num_t big_num { BN_new() }; - BN_set_word(big_num.get(), RSA_F4); - - auto rsa = RSA_new(); - RSA_generate_key_ex(rsa, key_bits, big_num.get(), nullptr); - EVP_PKEY_assign_RSA(pkey.get(), rsa); + EVP_PKEY_keygen_init(ctx.get()); + EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), key_bits); + EVP_PKEY_keygen(ctx.get(), &pkey); X509_set_version(x509.get(), 2); - ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 0); + + // Generate a real serial number to avoid SEC_ERROR_REUSED_ISSUER_AND_SERIAL with Firefox + bignum_t serial { BN_new() }; + BN_rand(serial.get(), 159, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); // 159 bits to fit in 20 bytes in DER format + BN_set_negative(serial.get(), 0); // Serial numbers must be positive + BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())); constexpr auto year = 60 * 60 * 24 * 365; #if OPENSSL_VERSION_NUMBER < 0x10100000L diff --git a/src/crypto.h b/src/crypto.h index 46259d1a7b7..8a2547b1bf1 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -30,6 +30,8 @@ using cipher_ctx_t = util::safe_ptr; using md_ctx_t = util::safe_ptr; using bio_t = util::safe_ptr; using pkey_t = util::safe_ptr; +using pkey_ctx_t = util::safe_ptr; +using bignum_t = util::safe_ptr; sha256_t hash(const std::string_view &plaintext); @@ -82,8 +84,8 @@ class cipher_t { class ecb_t : public cipher_t { public: - ecb_t() = default; - ecb_t(ecb_t &&) noexcept = default; + ecb_t() = default; + ecb_t(ecb_t &&) noexcept = default; ecb_t &operator=(ecb_t &&) noexcept = default; ecb_t(const aes_t &key, bool padding = true); @@ -94,8 +96,8 @@ class ecb_t : public cipher_t { class gcm_t : public cipher_t { public: - gcm_t() = default; - gcm_t(gcm_t &&) noexcept = default; + gcm_t() = default; + gcm_t(gcm_t &&) noexcept = default; gcm_t &operator=(gcm_t &&) noexcept = default; gcm_t(const crypto::aes_t &key, bool padding = true); @@ -113,8 +115,8 @@ class gcm_t : public cipher_t { class cbc_t : public cipher_t { public: - cbc_t() = default; - cbc_t(cbc_t &&) noexcept = default; + cbc_t() = default; + cbc_t(cbc_t &&) noexcept = default; cbc_t &operator=(cbc_t &&) noexcept = default; cbc_t(const crypto::aes_t &key, bool padding = true); diff --git a/src/main.cpp b/src/main.cpp index 58271f83d02..639688aaa15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,6 +101,7 @@ int entry(const char *name, int argc, char *argv[]) { } } // namespace version + void log_flush() { sink->flush(); } @@ -136,23 +137,71 @@ std::map