Compare commits

..

1 Commits

Author SHA1 Message Date
ReenigneArcher
07c0044df3 feat(installer/windows): add wix installer 2025-07-04 18:17:09 -04:00
108 changed files with 1134 additions and 1133 deletions

5
.gitattributes vendored
View File

@@ -1,5 +1,6 @@
# ensure Linux specific files are checked out with LF line endings
# ensure dockerfiles are checked out with LF line endings
Dockerfile text eol=lf
*.dockerfile text eol=lf
# ensure flatpak lint json files are checked out with LF line endings
*flatpak-lint-*.json text eol=lf
*.sh text eol=lf

View File

@@ -1,17 +0,0 @@
{
"problemMatcher": [
{
"owner": "copr-ci-gcc",
"pattern": [
{
"regexp": "^/?(?:[^/]+/){5}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
]
}

View File

@@ -1,17 +0,0 @@
{
"problemMatcher": [
{
"owner": "docker-gcc",
"pattern": [
{
"regexp": "^(?:#\\d+\\s+\\d+\\.\\d+\\s+)?/?(?:[^/]+/){2}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
]
}

View File

@@ -1,17 +0,0 @@
{
"problemMatcher": [
{
"owner": "gcc-strip3",
"pattern": [
{
"regexp": "^/?(?:[^/]+/){3}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
]
}

View File

@@ -1,29 +0,0 @@
{
"problemMatcher": [
{
"owner": "gcc",
"pattern": [
{
"regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
},
{
"owner": "doxygen",
"pattern": [
{
"regexp": "^.*?([A-Za-z]:[\\\\/][^:]+|[\\\\/][^:]+):(\\d+): ([a-zA-Z]+): (.+)$",
"file": 1,
"line": 2,
"severity": 3,
"message": 4
}
]
}
]
}

View File

@@ -20,6 +20,4 @@ jobs:
uses: LizardByte/.github/.github/workflows/__call-release-notifier.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_EMAIL: ${{ secrets.GH_BOT_EMAIL }}
GH_NAME: ${{ secrets.GH_BOT_NAME }}
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -26,6 +26,4 @@ jobs:
uses: LizardByte/.github/.github/workflows/__call-update-flathub-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_EMAIL: ${{ secrets.GH_BOT_EMAIL }}
GH_NAME: ${{ secrets.GH_BOT_NAME }}
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -26,6 +26,4 @@ jobs:
uses: LizardByte/.github/.github/workflows/__call-update-pacman-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_EMAIL: ${{ secrets.GH_BOT_EMAIL }}
GH_NAME: ${{ secrets.GH_BOT_NAME }}
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -16,10 +16,6 @@ on:
required: false
COPR_CLI_CONFIG:
required: false
GH_BOT_TOKEN:
required: false
VIRUSTOTAL_API_KEY:
required: false
concurrency:
group: "_${{ github.workflow }}-${{ github.ref }}"
@@ -38,35 +34,3 @@ jobs:
COPR_BETA_WEBHOOK_TOKEN: ${{ secrets.COPR_BETA_WEBHOOK_TOKEN }}
COPR_STABLE_WEBHOOK_TOKEN: ${{ secrets.COPR_STABLE_WEBHOOK_TOKEN }}
COPR_CLI_CONFIG: ${{ secrets.COPR_CLI_CONFIG }}
release:
name: Release
if:
github.event_name == 'release' &&
startsWith(github.repository, 'LizardByte/')
needs:
- call-copr-ci
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v5
with:
path: artifacts
pattern: build-*
merge-multiple: true
- name: Debug artifacts
run: ls -l artifacts
- name: Update GitHub Release
uses: LizardByte/actions/actions/release_create@v2025.715.25226
with:
allowUpdates: true
body: ${{ github.event.release.body }}
deleteOtherPreReleases: false
generateReleaseNotes: false
name: ${{ github.event.release.name }}
prerelease: true
tag: ${{ github.event.release.tag_name }}
token: ${{ secrets.GH_BOT_TOKEN }}
virustotal_api_key: ${{ secrets.VIRUSTOTAL_API_KEY }}

View File

@@ -73,16 +73,15 @@ jobs:
cmake \
flatpak
sudo su "$(whoami)" -c "flatpak --user remote-add --if-not-exists flathub \
https://flathub.org/repo/flathub.flatpakrepo
"
sudo su $(whoami) -c "flatpak --user remote-add --if-not-exists flathub \
https://flathub.org/repo/flathub.flatpakrepo"
sudo su "$(whoami)" -c "flatpak --user install -y flathub \
sudo su $(whoami) -c "flatpak --user install -y flathub \
org.flatpak.Builder \
org.freedesktop.Platform/${{ matrix.arch }}/${PLATFORM_VERSION} \
org.freedesktop.Sdk/${{ matrix.arch }}/${PLATFORM_VERSION} \
org.freedesktop.Sdk.Extension.node${NODE_VERSION}/${{ matrix.arch }}/${PLATFORM_VERSION} \
"
"
flatpak run org.flatpak.Builder --version
@@ -102,11 +101,9 @@ jobs:
flatpak-${{ matrix.arch }}-
- name: Configure Flatpak Manifest
env:
BRANCH: ${{ github.head_ref }}
run: |
# variables for manifest
branch="${{ env.BRANCH }}"
branch="${{ github.head_ref }}"
build_version=${{ inputs.release_version }}
commit=${{ inputs.release_commit }}
@@ -140,20 +137,19 @@ jobs:
- name: Debug Manifest
working-directory: build
run: cat "${APP_ID}.yml"
run: cat ${APP_ID}.yml
- name: Build Linux Flatpak
working-directory: build
run: |
echo "::add-matcher::.github/matchers/gcc-strip3.json"
sudo su "$(whoami)" -c "flatpak run org.flatpak.Builder \
sudo su $(whoami) -c "flatpak run org.flatpak.Builder \
--arch=${{ matrix.arch }} \
--force-clean \
--repo=repo \
--sandbox \
--stop-at=cuda build-sunshine ${APP_ID}.yml"
cp -r .flatpak-builder copy-of-flatpak-builder
sudo su "$(whoami)" -c "flatpak run org.flatpak.Builder \
sudo su $(whoami) -c "flatpak run org.flatpak.Builder \
--arch=${{ matrix.arch }} \
--force-clean \
--repo=repo \
@@ -161,16 +157,15 @@ jobs:
build-sunshine ${APP_ID}.yml"
rm -rf .flatpak-builder
mv copy-of-flatpak-builder .flatpak-builder
sudo su "$(whoami)" -c "flatpak build-bundle \
sudo su $(whoami) -c "flatpak build-bundle \
--arch=${{ matrix.arch }} \
./repo \
../artifacts/sunshine_${{ matrix.arch }}.flatpak ${APP_ID}"
sudo su "$(whoami)" -c "flatpak build-bundle \
sudo su $(whoami) -c "flatpak build-bundle \
--runtime \
--arch=${{ matrix.arch }} \
./repo \
../artifacts/sunshine_debug_${{ matrix.arch }}.flatpak ${APP_ID}.Debug"
echo "::remove-matcher owner=gcc-strip3::"
- name: Lint Flatpak
working-directory: build
@@ -182,7 +177,7 @@ jobs:
--exceptions \
--user-exceptions "${exceptions_file}" \
manifest \
"${APP_ID}.yml"
${APP_ID}.yml
echo "Linting flatpak repo"
# TODO: add arg
@@ -198,13 +193,13 @@ jobs:
if: matrix.arch == 'x86_64'
run: |
mkdir -p flathub/modules
cp "./build/generated-sources.json" "./flathub/"
cp "./build/package-lock.json" "./flathub/"
cp "./build/${APP_ID}.yml" "./flathub/"
cp "./build/${APP_ID}.metainfo.xml" "./flathub/"
cp "./packaging/linux/flatpak/README.md" "./flathub/"
cp "./packaging/linux/flatpak/flathub.json" "./flathub/"
cp -r "./packaging/linux/flatpak/modules/." "./flathub/modules/"
cp ./build/generated-sources.json ./flathub/
cp ./build/package-lock.json ./flathub/
cp ./build/${APP_ID}.yml ./flathub/
cp ./build/${APP_ID}.metainfo.xml ./flathub/
cp ./packaging/linux/flatpak/README.md ./flathub/
cp ./packaging/linux/flatpak/flathub.json ./flathub/
cp -r ./packaging/linux/flatpak/modules/. ./flathub/modules/
# submodules will need to be handled in the workflow that creates the PR
# create the archive

View File

@@ -36,6 +36,8 @@ jobs:
include:
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
# while GitHub has larger macOS runners, they are not available for our repos :(
- os_version: "13"
os_name: "macos"
- os_version: "14"
os_name: "macos"
- os_version: "15"
@@ -71,13 +73,9 @@ jobs:
brew install python3
- name: Configure formula
env:
HEAD_REF: ${{ github.head_ref }}
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_DEFAULT_BRANCH: ${{ github.event.pull_request.head.repo.default_branch }}
run: |
# variables for formula
branch="${{ env.HEAD_REF }}"
branch="${{ github.head_ref }}"
build_version=${{ inputs.release_version }}
commit=${{ inputs.release_commit }}
@@ -98,9 +96,9 @@ jobs:
else
echo "This is a PR event"
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
branch="${{ env.PR_HEAD_REF }}"
default_branch="${{ env.PR_DEFAULT_BRANCH }}"
tag="${{ env.PR_HEAD_REF }}"
branch="${{ github.event.pull_request.head.ref }}"
default_branch="${{ github.event.pull_request.head.repo.default_branch }}"
tag="${{ github.event.pull_request.head.ref }}"
fi
echo "Branch: ${branch}"
echo "Clone URL: ${clone_url}"
@@ -145,13 +143,12 @@ jobs:
export DISPLAY=:1
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
echo "DISPLAY=${DISPLAY}" >> "${GITHUB_ENV}"
echo "DISPLAY=${DISPLAY}" >> $GITHUB_ENV
- run: echo "::add-matcher::.github/matchers/gcc-strip3.json"
- name: Validate Homebrew Formula
id: test
if: matrix.release != true
uses: LizardByte/actions/actions/release_homebrew@v2025.715.25226
uses: LizardByte/actions/actions/release_homebrew@v2025.703.21447
with:
formula_file: ${{ github.workspace }}/homebrew/sunshine.rb
git_email: ${{ secrets.GIT_EMAIL }}
@@ -159,11 +156,9 @@ jobs:
publish: false
token: ${{ secrets.GH_TOKEN }}
validate: true
- run: echo "::remove-matcher owner=gcc-strip3::"
- name: Setup python
id: python
if: false
uses: actions/setup-python@v5
with:
python-version: '3.11'
@@ -225,10 +220,16 @@ jobs:
echo "New formula:"
cat $formula_file
- name: Upload Artifacts (Beta)
if: matrix.release
uses: actions/upload-artifact@v4
- name: Upload Homebrew Beta Formula
if: >-
github.repository_owner == 'LizardByte' &&
matrix.release &&
inputs.publish_release == 'true'
uses: LizardByte/actions/actions/release_homebrew@v2025.703.21447
with:
name: beta-Homebrew
path: homebrew/
if-no-files-found: error
formula_file: ${{ github.workspace }}/homebrew/sunshine-beta.rb
git_email: ${{ secrets.GIT_EMAIL }}
git_username: ${{ secrets.GIT_USERNAME }}
publish: true
token: ${{ secrets.GH_TOKEN }}
validate: false

View File

@@ -79,8 +79,8 @@ jobs:
--enable-x11 \
--enable-glx \
--enable-wayland \
--without-legacy
make -j "$(nproc)"
--without-legacy # emgd, nvctrl, fglrx
make -j $(nproc)
sudo make install
cd .. && rm -rf libva-*
@@ -91,7 +91,6 @@ jobs:
COMMIT: ${{ inputs.release_commit }}
run: |
chmod +x ./scripts/linux_build.sh
echo "::add-matcher::.github/matchers/gcc.json"
./scripts/linux_build.sh \
--publisher-name='${{ github.repository_owner }}' \
--publisher-website='https://app.lizardbyte.dev' \
@@ -99,13 +98,12 @@ jobs:
--skip-cleanup \
--skip-package \
--ubuntu-test-repo ${{ matrix.EXTRA_ARGS }}
echo "::remove-matcher owner=gcc::"
- name: Set AppImage Version
if: matrix.name == 'AppImage'
run: |
version=${{ inputs.release_version }}
echo "VERSION=${version}" >> "${GITHUB_ENV}"
echo "VERSION=${version}" >> $GITHUB_ENV
- name: Package Linux - AppImage
if: matrix.name == 'AppImage'

View File

@@ -199,12 +199,12 @@ jobs:
ignore_list=$(IFS=,; echo "${ignore_packages[*]}")
# install pinned dependencies
if [ -n "${tarballs}" ]; then
pacman -U --noconfirm "${tarballs}"
if [ -n "$tarballs" ]; then
pacman -U --noconfirm ${tarballs}
fi
# Only add --ignore if we have packages to ignore
if [ -n "${ignore_list}" ]; then
if [ -n "$ignore_list" ]; then
pacman -Syu --noconfirm --ignore="${ignore_list}" "${dependencies[@]}"
else
pacman -Syu --noconfirm "${dependencies[@]}"
@@ -236,6 +236,11 @@ jobs:
# Clean up
Remove-Item -Path doxygen-setup.exe
- name: Setup dotnet # needed for wix
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.x'
- name: Setup python
id: setup-python
uses: actions/setup-python@v5
@@ -251,7 +256,7 @@ jobs:
# step output
echo "python-path=${python_path}"
echo "python-path=${python_path}" >> "${GITHUB_OUTPUT}"
echo "python-path=${python_path}" >> $GITHUB_OUTPUT
- name: Build Windows
shell: msys2 {0}
@@ -272,9 +277,7 @@ jobs:
-DSUNSHINE_PUBLISHER_NAME='${{ github.repository_owner }}' \
-DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \
-DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support'
echo "::add-matcher::.github/matchers/gcc.json"
ninja -C build
echo "::remove-matcher owner=gcc::"
- name: Package Windows
shell: msys2 {0}
@@ -284,12 +287,19 @@ jobs:
# package
cpack -G NSIS
cpack -G WIX
cpack -G ZIP
# move
mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe
mv ./cpack_artifacts/Sunshine.msi ../artifacts/Sunshine-${{ matrix.name }}-installer.msi
mv ./cpack_artifacts/Sunshine.zip ../artifacts/Sunshine-${{ matrix.name }}-portable.zip
- name: Debug wix
if: always()
shell: msys2 {0}
run: cat /d/a/Sunshine/Sunshine/build/cpack_artifacts/_CPack_Packages/win64/WIX/wix.log
- name: Run tests
id: test
shell: msys2 {0}

View File

@@ -43,7 +43,7 @@ jobs:
- name: Release Setup
id: release-setup
uses: LizardByte/actions/actions/release_setup@v2025.715.25226
uses: LizardByte/actions/actions/release_setup@v2025.703.21447
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -56,7 +56,6 @@ jobs:
uses: LizardByte/.github/.github/workflows/__call-docker.yml@master
with:
maximize_build_space: true
maximize_build_space_root_reserve_size: 32768
publish_release: ${{ needs.release-setup.outputs.publish_release }}
release_commit: ${{ needs.release-setup.outputs.release_commit }}
release_tag: ${{ needs.release-setup.outputs.release_tag }}
@@ -137,6 +136,8 @@ jobs:
include:
- name: Linux-AppImage
coverage: true
- name: Homebrew-macos-13
coverage: false
- name: Homebrew-macos-14
coverage: false
- name: Homebrew-macos-15
@@ -150,7 +151,7 @@ jobs:
uses: actions/checkout@v4
- name: Download coverage artifact
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: coverage-${{ matrix.name }}
path: _coverage
@@ -185,13 +186,14 @@ jobs:
- release-setup
- build-docker
- build-linux
- build-linux-copr
- build-linux-flatpak
- build-homebrew
- build-windows
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: build-*
@@ -201,7 +203,7 @@ jobs:
run: ls -l artifacts
- name: Create/Update GitHub Release
uses: LizardByte/actions/actions/release_create@v2025.715.25226
uses: LizardByte/actions/actions/release_create@v2025.703.21447
with:
allowUpdates: false
body: ${{ needs.release-setup.outputs.release_body }}
@@ -211,30 +213,3 @@ jobs:
tag: ${{ needs.release-setup.outputs.release_tag }}
token: ${{ secrets.GH_BOT_TOKEN }}
virustotal_api_key: ${{ secrets.VIRUSTOTAL_API_KEY }}
release-homebrew-beta:
name: Release Homebrew Beta
if:
needs.release-setup.outputs.publish_release == 'true' &&
startsWith(github.repository, 'LizardByte/')
needs:
- release-setup
- build-homebrew
- release
runs-on: ubuntu-latest
steps:
- name: Download homebrew artifacts
uses: actions/download-artifact@v5
with:
name: beta-Homebrew
path: homebrew
- name: Upload Homebrew Beta Formula
uses: LizardByte/actions/actions/release_homebrew@v2025.715.25226
with:
formula_file: ${{ github.workspace }}/homebrew/sunshine-beta.rb
git_email: ${{ secrets.GH_BOT_EMAIL }}
git_username: ${{ secrets.GH_BOT_NAME }}
publish: true
token: ${{ secrets.GH_BOT_TOKEN }}
validate: false

View File

@@ -48,9 +48,9 @@ jobs:
if [ -f "${{ env.file }}" ];
then
rm ${{ env.file }}
echo "new_file=false" >> "${GITHUB_ENV}"
echo "new_file=false" >> $GITHUB_ENV
else
echo "new_file=true" >> "${GITHUB_ENV}"
echo "new_file=true" >> $GITHUB_ENV
fi
# extract the new strings
@@ -67,7 +67,7 @@ jobs:
# set the variable with minimal output, replacing `\t` with ` `
OUTPUT=$(git diff --numstat locale/sunshine.po | sed -e "s#\t# #g")
echo "git_diff=${OUTPUT}" >> "${GITHUB_ENV}"
echo "git_diff=${OUTPUT}" >> $GITHUB_ENV
- name: git reset
# only run if a single line changed (date/time) and file already existed
@@ -79,7 +79,7 @@ jobs:
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> "${GITHUB_OUTPUT}"
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Create/Update Pull Request
uses: peter-evans/create-pull-request@v7

View File

@@ -13,7 +13,7 @@
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine"><img src="https://img.shields.io/flathub/v/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub Version"></a>
<a href="https://github.com/microsoft/winget-pkgs/tree/master/manifests/l/LizardByte/Sunshine"><img src="https://img.shields.io/winget/v/LizardByte.Sunshine?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHuSURBVFhH7ZfNTtRQGIYZiMDwN/IrCAqIhMSNKxcmymVwG+5dcDVsWHgDrtxwCYQVl+BChzDEwSnPY+eQ0sxoOz1mQuBNnpyvTdvz9jun5/SrjfxnJUkyQbMEz2ELduF1l0YUA3QyTrMAa2AnPtyOXsELeAYNyKtV2EC3k3lYgTOwg09ghy/BTp7CKBRV844BOpmmMV2+ySb4BmInG7AKY7AHH+EYqqhZo9PPBG/BVDlOizAD/XQFmnoPXzxRQX8M/CCYS48L6RIc4ygGHK9WGg9HZSZMUNRPVwNJGg5Hg2Qgqh4N3FsDsb6EmgYm07iwwvUxstdxJTwgmILf4CfZ6bb5OHANX8GN5x20IVxnG8ge94pt2xpwU3GnCwayF4Q2G2vgFLzHndFzQdk4q77nNfCdwL28qNyMtmEf3A1/QV5FjDiPWo5jrwf8TWZChTlgJvL4F9QL50/A43qVidTvLcuoM2wDQ1+IkgefgUpLcYwMVBqCKNJA2b0gKNocOIITOIef8C/F/CdMbh/GklynsSawKLHS8d9/B1x2LUqsfFyy3TMsWj5A1cLkotDbYO4JjWWZlZEGv8EbOIR1CAVN2eG8W5oNKgxaeC6DmTJjZs7ixUxpznLPLT+v4sXpoMLcLI3mzFSonDXIEI/M3QCIO4YuimBJ/gAAAABJRU5ErkJggg==" alt="Winget Version"></a>
<a href="https://gurubase.io/g/sunshine"><img src="https://img.shields.io/badge/Gurubase-Ask%20Guru-ef1a1b?style=for-the-badge&logo=data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIABgAGAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AOLqSO3mlilljido4QGkYDIQEgAn05IH41seFo7aS+uRKlrJci2Y2cd2QImlyOGyQPu7sA8ZxXapAlvpThbPRkv7nTQWhDoIZZRc/XaSAOmcZGOnFfP06XMr3P17F5iqE+Tl1uuvf9Lde55dRW74pit4r61EcdtFdG2U3kVqQY0lyeBgkD5duQOASawqykuV2O6jV9rTU0rXLNjf3Om3QubSXy5QCudoYEEYIIOQR7GnahqV3qk6zXk3mOqhFAUKqqOyqAAByeAKqUUXdrFezhz89lfv1+8KKKKRZ//Z" alt="Gurubase"></a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/ci.yml?query=branch%3Amaster"><img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/ci.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (CI)"></a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/CI.yml?query=branch%3Amaster"><img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/CI.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (CI)"></a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/localize.yml?query=branch%3Amaster"><img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/localize.yml.svg?branch=master&label=localize%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (localize)"></a>
<a href="https://docs.lizardbyte.dev/projects/sunshine"><img src="https://img.shields.io/readthedocs/sunshinestream.svg?label=Docs&style=for-the-badge&logo=readthedocs" alt="Read the Docs"></a>
<a href="https://codecov.io/gh/LizardByte/Sunshine"><img src="https://img.shields.io/codecov/c/gh/LizardByte/Sunshine?token=SMGXQ5NVMJ&style=for-the-badge&logo=codecov&label=codecov" alt="Codecov"></a>
@@ -72,13 +72,13 @@ LizardByte has the full documentation hosted on [Read the Docs](https://docs.liz
<td>Windows: 10+ (Windows Server does not support virtual gamepads)</td>
</tr>
<tr>
<td>macOS: 14+</td>
<td>macOS: 13+</td>
</tr>
<tr>
<td>Linux/Debian: 13+ (trixie)</td>
<td>Linux/Debian: 12+ (bookworm)</td>
</tr>
<tr>
<td>Linux/Fedora: 41+</td>
<td>Linux/Fedora: 40+</td>
</tr>
<tr>
<td>Linux/Ubuntu: 22.04+ (jammy)</td>

View File

@@ -85,27 +85,18 @@ if(CUDA_FOUND)
add_compile_definitions(SUNSHINE_BUILD_CUDA)
endif()
# libdrm is required for both DRM (KMS) and Wayland
if(${SUNSHINE_ENABLE_DRM} OR ${SUNSHINE_ENABLE_WAYLAND})
find_package(LIBDRM REQUIRED)
else()
set(LIBDRM_FOUND OFF)
endif()
if(LIBDRM_FOUND)
include_directories(SYSTEM ${LIBDRM_INCLUDE_DIRS})
list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES})
endif()
# drm
if(${SUNSHINE_ENABLE_DRM})
find_package(LIBDRM REQUIRED)
find_package(LIBCAP REQUIRED)
else()
set(LIBDRM_FOUND OFF)
set(LIBCAP_FOUND OFF)
endif()
if(LIBDRM_FOUND AND LIBCAP_FOUND)
add_compile_definitions(SUNSHINE_BUILD_DRM)
include_directories(SYSTEM ${LIBCAP_INCLUDE_DIRS})
list(APPEND PLATFORM_LIBRARIES ${LIBCAP_LIBRARIES})
include_directories(SYSTEM ${LIBDRM_INCLUDE_DIRS} ${LIBCAP_INCLUDE_DIRS})
list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES} ${LIBCAP_LIBRARIES})
list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/linux/kmsgrab.cpp")
list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1)

View File

@@ -45,7 +45,6 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "\
libcap2, \
libcurl4, \
libdrm2, \
libgbm1, \
libevdev2, \
libnuma1, \
libopus0, \
@@ -66,7 +65,6 @@ set(CPACK_RPM_PACKAGE_REQUIRES "\
libva >= 2.14.0, \
libwayland-client >= 1.20.0, \
libX11 >= 1.7.3.1, \
mesa-libgbm >= 25.0.7, \
miniupnpc >= 2.2.4, \
numactl-libs >= 2.0.14, \
openssl >= 3.0.2, \

View File

@@ -4,20 +4,6 @@ install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application)
# Hardening: include zlib1.dll (loaded via LoadLibrary() in openssl's libcrypto.a)
install(FILES "${ZLIB}" DESTINATION "." COMPONENT application)
# ViGEmBus installer
set(VIGEMBUS_INSTALLER "${CMAKE_BINARY_DIR}/vigembus_installer.exe")
file(DOWNLOAD
"https://github.com/nefarius/ViGEmBus/releases/download/v1.21.442.0/ViGEmBus_1.21.442_x64_x86_arm64.exe"
${VIGEMBUS_INSTALLER}
SHOW_PROGRESS
EXPECTED_HASH SHA256=155c50f1eec07bdc28d2f61a3e3c2c6c132fee7328412de224695f89143316bc
TIMEOUT 60
)
install(FILES ${VIGEMBUS_INSTALLER}
DESTINATION "scripts"
RENAME "vigembus_installer.exe"
COMPONENT gamepad)
# Adding tools
install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi)
install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio)

View File

@@ -15,8 +15,7 @@ SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" add'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"'
nsExec::ExecToLog \
'powershell.exe -ExecutionPolicy Bypass -File \\\"$INSTDIR\\\\scripts\\\\install-gamepad.ps1\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-gamepad.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\autostart-service.bat\\\"'
NoController:
@@ -32,9 +31,7 @@ set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove Virtual Gamepad?' \
/SD IDNO IDNO NoGamepad
nsExec::ExecToLog \
'powershell.exe -ExecutionPolicy Bypass -File \\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.ps1\\\"'; \
skipped if no
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.bat\\\"'; skipped if no
NoGamepad:
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \

View File

@@ -1,4 +1,72 @@
# WIX Packaging
# see options at: https://cmake.org/cmake/help/latest/cpack_gen/wix.html
# TODO: Replace nsis with wix
set(CPACK_WIX_VERSION 4)
set(WIX_VERSION 4.0.4)
set(WIX_UI_VERSION 4.0.4) # extension versioning is independent of the WiX version
set(WIX_BUILD_PARENT_DIRECTORY "${CPACK_PACKAGE_DIRECTORY}/_CPack_Packages/win64")
set(WIX_BUILD_DIRECTORY "${WIX_BUILD_PARENT_DIRECTORY}/WIX")
# Download and install WiX tools locally in the build directory
set(WIX_TOOL_PATH "${CMAKE_BINARY_DIR}/.wix")
file(MAKE_DIRECTORY ${WIX_TOOL_PATH})
# find dotnet
find_program(DOTNET_EXECUTABLE dotnet REQUIRED HINTS "C:/Program Files/dotnet")
# Install WiX locally using dotnet
execute_process(
COMMAND ${DOTNET_EXECUTABLE} tool install --tool-path ${WIX_TOOL_PATH} wix --version ${WIX_VERSION}
ERROR_VARIABLE WIX_INSTALL_OUTPUT
RESULT_VARIABLE WIX_INSTALL_RESULT
)
if(NOT WIX_INSTALL_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to install WiX tools locally.
WiX packaging may not work correctly, error: ${WIX_INSTALL_OUTPUT}")
endif()
# Install WiX UI Extension
execute_process(
COMMAND "${WIX_TOOL_PATH}/wix" extension add WixToolset.UI.wixext/${WIX_UI_VERSION}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
ERROR_VARIABLE WIX_UI_INSTALL_OUTPUT
RESULT_VARIABLE WIX_UI_INSTALL_RESULT
)
if(NOT WIX_UI_INSTALL_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to install WiX UI extension, error: ${WIX_UI_INSTALL_OUTPUT}")
endif()
# Set WiX-specific variables
set(CPACK_WIX_ROOT "${WIX_TOOL_PATH}")
set(CPACK_WIX_UPGRADE_GUID "512A3D1B-BE16-401B-A0D1-59BBA3942FB8")
# Help/Support URLs
set(CPACK_WIX_HELP_LINK "https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2getting__started.html")
set(CPACK_WIX_PRODUCT_URL "${CMAKE_PROJECT_HOMEPAGE_URL}")
set(CPACK_WIX_PROGRAM_MENU_FOLDER "LizardByte")
set(CPACK_WIX_EXTENSIONS
"WixToolset.UI.wixext"
)
message(STATUS "cpack package directory: ${CPACK_PACKAGE_DIRECTORY}")
# copy custom wxs files to the build directory
file(COPY "${CMAKE_CURRENT_LIST_DIR}/wix_resources/"
DESTINATION "${WIX_BUILD_PARENT_DIRECTORY}/")
set(CPACK_WIX_EXTRA_SOURCES
"${WIX_BUILD_PARENT_DIRECTORY}/custom-actions.wxs"
"${WIX_BUILD_PARENT_DIRECTORY}/custom-shortcuts.wxs"
)
# Copy root LICENSE and rename to have .txt extension
file(COPY "${CMAKE_SOURCE_DIR}/LICENSE"
DESTINATION "${CMAKE_BINARY_DIR}")
file(RENAME "${CMAKE_BINARY_DIR}/LICENSE" "${CMAKE_BINARY_DIR}/LICENSE.txt")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE.txt") # cpack will covert this to an RTF if it is txt
# https://cmake.org/cmake/help/latest/cpack_gen/wix.html#variable:CPACK_WIX_ARCHITECTURE
set(CPACK_WIX_ARCHITECTURE "x64")

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<?include "WIX/cpack_variables.wxi"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
<Fragment Id="CustomActionsFragment">
<CustomAction Id='InstallService'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\install-service.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='ConfigFirewall'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\add-firewall-rule.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='InstallGamepad'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\install-gamepad.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='AutostartService'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\autostart-service.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='MigrateConfig'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\migrate-config.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='UpdatePath'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\update-path.bat add"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='ResetPermissions'
ExeCommand='cmd.exe /c "icacls \"[INSTALL_ROOT]\" /reset"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='UninstallService'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\uninstall-service.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='RemoveFirewall'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\delete-firewall-rule.bat"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='RestoreNvPrefs'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]$(var.CPACK_PACKAGE_NAME).exe --restore-nvprefs-undo"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<CustomAction Id='RemovePathUpdate'
ExeCommand='cmd.exe /c "[INSTALL_ROOT]scripts\update-path.bat remove"'
Directory='INSTALL_ROOT'
Execute='deferred'
Return='check'
Impersonate='no' />
<InstallExecuteSequence>
<Custom Action='ResetPermissions' After='InstallFiles' Condition="NOT Installed" />
<Custom Action='UpdatePath' After='ResetPermissions' Condition="NOT Installed" />
<Custom Action='MigrateConfig' After='UpdatePath' Condition="NOT Installed" />
<Custom Action='ConfigFirewall' After='MigrateConfig' Condition="NOT Installed" />
<Custom Action='InstallGamepad' After='ConfigFirewall' Condition="NOT Installed" />
<Custom Action='InstallService' After='InstallGamepad' Condition="NOT Installed" />
<Custom Action='AutostartService' After='InstallService' Condition="NOT Installed" />
<Custom Action='RemoveFirewall' Before='RemoveFiles' Condition="REMOVE" />
<Custom Action='UninstallService' Before='RemoveFiles' Condition="REMOVE" />
<Custom Action='RestoreNvPrefs' Before='RemoveFiles' Condition="REMOVE" />
<Custom Action='RemovePathUpdate' Before='RemoveFiles' Condition="REMOVE" />
</InstallExecuteSequence>
</Fragment>
</Wix>

View File

@@ -0,0 +1,23 @@
<?xml version='1.0' encoding='UTF-8'?>
<?include "WIX/cpack_variables.wxi"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment Id="CustomShortcutsFragment">
<StandardDirectory Id='ProgramMenuFolder'>
<Directory Id='ApplicationProgramsFolder' Name='$(var.CPACK_PACKAGE_VENDOR)'>
<Component Id='ApplicationShortcut' Guid='*'>
<Shortcut Id='ApplicationStartMenuShortcut'
Name='$(var.CPACK_PACKAGE_NAME)'
Description='Self-hosted game stream host for Moonlight'
Target='[INSTALL_ROOT]$(var.CPACK_PACKAGE_NAME).exe'
Arguments='--shortcut'
WorkingDirectory='INSTALL_ROOT'/>
<RemoveFolder Id='ApplicationProgramsFolder' On='uninstall'/>
<RegistryValue Root='HKCU' Key='Software\\LizardByte\\$(var.CPACK_PACKAGE_NAME)'
Name='installed' Type='integer' Value='1' KeyPath='yes'/>
</Component>
</Directory>
</StandardDirectory>
</Fragment>
</Wix>

View File

@@ -1,18 +1,18 @@
# Set build variables if env variables are defined
# These are used in configured files such as manifests for different packages
if(DEFINED ENV{BRANCH})
if(DEFINED ENV{BRANCH}) # cmake-lint: disable=W0106
set(GITHUB_BRANCH $ENV{BRANCH})
endif()
if(DEFINED ENV{BUILD_VERSION}) # cmake-lint: disable=W0106
set(BUILD_VERSION $ENV{BUILD_VERSION})
endif()
if(DEFINED ENV{CLONE_URL})
if(DEFINED ENV{CLONE_URL}) # cmake-lint: disable=W0106
set(GITHUB_CLONE_URL $ENV{CLONE_URL})
endif()
if(DEFINED ENV{COMMIT})
if(DEFINED ENV{COMMIT}) # cmake-lint: disable=W0106
set(GITHUB_COMMIT $ENV{COMMIT})
endif()
if(DEFINED ENV{TAG})
if(DEFINED ENV{TAG}) # cmake-lint: disable=W0106
set(GITHUB_TAG $ENV{TAG})
endif()
@@ -56,11 +56,11 @@ else()
if(NOT GIT_DESCRIBE_ERROR_CODE)
MESSAGE("Sunshine Branch: ${GIT_DESCRIBE_BRANCH}")
if(NOT GIT_DESCRIBE_BRANCH STREQUAL "master")
set(PROJECT_VERSION ${PROJECT_VERSION}.${GIT_DESCRIBE_VERSION})
set(PROJECT_VERSION ${PROJECT_VERSION}-${GIT_DESCRIBE_VERSION})
MESSAGE("Sunshine Version: ${GIT_DESCRIBE_VERSION}")
endif()
if(GIT_IS_DIRTY)
set(PROJECT_VERSION ${PROJECT_VERSION}.dirty)
set(PROJECT_VERSION ${PROJECT_VERSION}-dirty)
MESSAGE("Git tree is dirty!")
endif()
else()

View File

@@ -27,7 +27,7 @@ endif()
target_link_libraries(sunshine ${SUNSHINE_EXTERNAL_LIBRARIES} ${EXTRA_LIBS})
target_compile_definitions(sunshine PUBLIC ${SUNSHINE_DEFINITIONS})
set_target_properties(sunshine PROPERTIES CXX_STANDARD 23
set_target_properties(sunshine PROPERTIES CXX_STANDARD 20
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR})

View File

@@ -32,6 +32,7 @@ ENV CLONE_URL=${CLONE_URL}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# hadolint ignore=SC2016
RUN <<_SETUP
#!/bin/bash
set -e
@@ -41,7 +42,6 @@ useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
# patch the build flags
# shellcheck disable=SC2016
sed -i 's,#MAKEFLAGS="-j2",MAKEFLAGS="-j$(nproc)",g' /etc/makepkg.conf
# install dependencies

View File

@@ -3,8 +3,8 @@
# platforms: linux/amd64
# platforms_pr: linux/amd64
# no-cache-filters: toolchain-base,toolchain
ARG BASE=debian
ARG TAG=trixie-slim
ARG BASE=ubuntu
ARG TAG=22.04
FROM ${BASE}:${TAG} AS toolchain-base
ENV DEBIAN_FRONTEND=noninteractive
@@ -19,17 +19,18 @@ ENV DISPLAY=:0
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# install dependencies
# hadolint ignore=SC1091
RUN <<_DEPS
#!/bin/bash
set -e
apt-get update -y
apt-get install -y --no-install-recommends \
build-essential \
cmake=3.31.* \
cmake=3.22.* \
ca-certificates \
doxygen \
gcc=4:14.2.* \
g++=4:14.2.* \
gcc=4:11.2.* \
g++=4:11.2.* \
gdb \
git \
graphviz \
@@ -59,13 +60,21 @@ apt-get install -y --no-install-recommends \
xvfb
apt-get clean
rm -rf /var/lib/apt/lists/*
# Install Node
wget --max-redirect=0 -qO- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
source "$HOME/.nvm/nvm.sh"
nvm install node
nvm use node
nvm alias default node
_DEPS
# install cuda
WORKDIR /build/cuda
# versions: https://developer.nvidia.com/cuda-toolkit-archive
ENV CUDA_VERSION="12.9.1"
ENV CUDA_BUILD="575.57.08"
ENV CUDA_VERSION="11.8.0"
ENV CUDA_BUILD="520.61.05"
# hadolint ignore=SC3010
RUN <<_INSTALL_CUDA
#!/bin/bash
set -e
@@ -76,31 +85,18 @@ if [[ "${TARGETPLATFORM}" == 'linux/arm64' ]]; then
fi
url="${cuda_prefix}${CUDA_VERSION}/local_installers/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux${cuda_suffix}.run"
echo "cuda url: ${url}"
tmpfile="/tmp/cuda.run"
wget "$url" --progress=bar:force:noscroll --show-progress -O "$tmpfile"
chmod a+x "${tmpfile}"
"${tmpfile}" --silent --toolkit --toolkitpath=/usr/local --no-opengl-libs --no-man-page --no-drm
rm -f "${tmpfile}"
wget "$url" --progress=bar:force:noscroll -q --show-progress -O ./cuda.run
chmod a+x ./cuda.run
./cuda.run --silent --toolkit --toolkitpath=/usr/local --no-opengl-libs --no-man-page --no-drm
rm ./cuda.run
_INSTALL_CUDA
WORKDIR /
# install node
RUN <<_INSTALL_NODE
#!/bin/bash
set -e
wget --max-redirect=0 -qO- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
source "$HOME/.nvm/nvm.sh"
nvm install node
nvm use node
nvm alias default node
_INSTALL_NODE
WORKDIR /toolchain
# Create a shell script that starts Xvfb and then runs a shell
# Write a shell script that starts Xvfb and then runs a shell
RUN <<_ENTRYPOINT
#!/bin/bash
set -e
cat <<EOF > entrypoint.sh
cat <<EOF > /entrypoint.sh
#!/bin/bash
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
if [ "\$#" -eq 0 ]; then
@@ -111,11 +107,11 @@ fi
EOF
# Make the script executable
chmod +x entrypoint.sh
chmod +x /entrypoint.sh
# Note about CLion
echo "ATTENTION: CLion will override the entrypoint, you can disable this in the toolchain settings"
_ENTRYPOINT
# Use the shell script as the entrypoint
ENTRYPOINT ["/toolchain/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -4,7 +4,7 @@
# platforms_pr: linux/amd64
# no-cache-filters: sunshine-base,artifacts,sunshine
ARG BASE=debian
ARG TAG=trixie
ARG TAG=bookworm
FROM ${BASE}:${TAG} AS sunshine-base
ENV DEBIAN_FRONTEND=noninteractive
@@ -32,7 +32,6 @@ RUN <<_BUILD
set -e
chmod +x ./scripts/linux_build.sh
./scripts/linux_build.sh \
--cuda-patches \
--publisher-name='LizardByte' \
--publisher-website='https://app.lizardbyte.dev' \
--publisher-issue-url='https://app.lizardbyte.dev/support' \
@@ -43,6 +42,7 @@ _BUILD
# run tests
WORKDIR /build/sunshine/build/tests
# hadolint ignore=SC1091
RUN <<_TEST
#!/bin/bash
set -e

View File

@@ -35,14 +35,14 @@ chmod +x ./scripts/linux_build.sh
--publisher-name='LizardByte' \
--publisher-website='https://app.lizardbyte.dev' \
--publisher-issue-url='https://app.lizardbyte.dev/support' \
--sudo-off \
--ubuntu-test-repo
--sudo-off
apt-get clean
rm -rf /var/lib/apt/lists/*
_BUILD
# run tests
WORKDIR /build/sunshine/build/tests
# hadolint ignore=SC1091
RUN <<_TEST
#!/bin/bash
set -e

View File

@@ -42,6 +42,7 @@ _BUILD
# run tests
WORKDIR /build/sunshine/build/tests
# hadolint ignore=SC1091
RUN <<_TEST
#!/bin/bash
set -e

View File

@@ -3,15 +3,6 @@ Sunshine binaries are built using [CMake](https://cmake.org) and requires `cmake
## Building Locally
### Compiler
It is recommended to use one of the following compilers:
| Compiler | Version |
|:------------|:--------|
| GCC | 13+ |
| Clang | 17+ |
| Apple Clang | 15+ |
### Dependencies
#### Linux
@@ -25,7 +16,7 @@ Sunshine requires CUDA Toolkit for NVFBC capture. There are two caveats to CUDA:
1. The version installed depends on the version of GCC.
2. The version of CUDA you use will determine compatibility with various GPU generations.
At the time of writing, the recommended version to use is CUDA ~12.9.
At the time of writing, the recommended version to use is CUDA ~11.8.
See [CUDA compatibility](https://docs.nvidia.com/deploy/cuda-compatibility/index.html) for more info.
@tip{To install older versions, select the appropriate run file based on your desired CUDA version and architecture
@@ -147,9 +138,12 @@ ninja -C build
```}
}}
@tab{Windows | @tabs{
@tab{Installer | ```bash
@tab{NSIS Installer | ```bash
cpack -G NSIS --config ./build/CPackConfig.cmake
```}
@tab{WiX Installer | ```bash
cpack -G WIX --config ./build/CPackConfig.cmake
```}
@tab{Portable | ```bash
cpack -G ZIP --config ./build/CPackConfig.cmake
```}

View File

@@ -1270,7 +1270,7 @@ editing the `conf` file in a text editor. Use the examples as reference.
<td colspan="2">
Remap the requested resolution and FPS to another display mode.<br>
Depending on the [dd_resolution_option](#dd_resolution_option) and
[dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping
[dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping
groups are available:
<ul>
<li>`mixed` - both options are set to `auto`.</li>
@@ -1281,7 +1281,7 @@ editing the `conf` file in a text editor. Use the examples as reference.
`refresh_rate_only` - only [dd_refresh_rate_option](#dd_refresh_rate_option) is set to `auto`.
</li>
</ul>
For each of those groups, a list of fields can be configured to perform remapping:
For each of those groups, a list of fields can be configured to perform remapping:
<ul>
<li>
`requested_resolution` - resolution that needs to be matched in order to use this remapping entry.
@@ -1291,10 +1291,10 @@ editing the `conf` file in a text editor. Use the examples as reference.
<li>`final_refresh_rate` - refresh rate value to be used if the entry was matched.</li>
</ul>
If `requested_*` field is left empty, it will match <b>everything</b>.<br>
If `final_*` field is left empty, the original value will not be remapped and either a requested, manual
or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered
If `final_*` field is left empty, the original value will not be remapped and either a requested, manual
or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered
invalid.<br>
@note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution`
@note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution`
field to be considered.}
@note{First entry to be matched in the list is the one that will be used.}
@tip{`requested_resolution` and `final_resolution` can be omitted for `refresh_rate_only` group.}
@@ -1371,32 +1371,6 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>
### minimum_fps_target
<table>
<tr>
<td>Description</td>
<td colspan="2">
Sunshine tries to save bandwidth when content on screen is static or a low framerate. Because many clients expect a constant stream of video frames, a certain amount of duplicate frames are sent when this happens. This setting controls the lowest effective framerate a stream can reach.
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
0
@endcode</td>
</tr>
<tr>
<td rowspan="3">Choices</td>
<td>0</td>
<td>Use half the stream's FPS as the minimum target.</td>
</tr>
<tr>
<td>1-1000</td>
<td>Specify your own value. The real minimum may differ from this value.</td>
</tr>
</table>
## Network
### upnp

View File

@@ -31,7 +31,7 @@ See [Docker](../DOCKER_README.md) for more information.
CUDA is used for NVFBC capture.
@tip{See [CUDA GPUS](https://developer.nvidia.com/cuda-gpus) to cross-reference Compute Capability to your GPU.
The table below applies to packages provided by LizardByte. If you use an official LizardByte package, then you do not
The table below applies to packages provided by LizardByte. If you use an official LizardByte package then you do not
need to install CUDA.}
<table>
@@ -43,9 +43,9 @@ need to install CUDA.}
<th>Package</th>
</tr>
<tr>
<td rowspan="8">12.9.1</td>
<td rowspan="8">575.57.08</td>
<td rowspan="8">50;52;60;61;62;70;72;75;80;86;87;89;90</td>
<td rowspan="3">11.8.0</td>
<td rowspan="3">450.80.02</td>
<td rowspan="3">35;50;52;60;61;62;70;72;75;80;86;87;89;90</td>
<td>sunshine.AppImage</td>
</tr>
<tr>
@@ -55,18 +55,27 @@ need to install CUDA.}
<td>sunshine-ubuntu-24.04-{arch}.deb</td>
</tr>
<tr>
<td>sunshine-debian-trixie-{arch}.deb</td>
<td rowspan="1">12.0.0</td>
<td rowspan="1">525.60.13</td>
<td rowspan="5">50;52;60;61;62;70;72;75;80;86;87;89;90</td>
<td>sunshine-debian-bookworm-{arch}.deb</td>
</tr>
<tr>
<td rowspan="2">12.6.2</td>
<td rowspan="2">560.35.03</td>
<td>sunshine_{arch}.flatpak</td>
</tr>
<tr>
<td>Sunshine (copr - Fedora 41)</td>
</tr>
<tr>
<td rowspan="1">12.8.1</td>
<td rowspan="1">570.124.06</td>
<td>Sunshine (copr - Fedora 42)</td>
</tr>
<tr>
<td rowspan="1">12.9.1</td>
<td rowspan="1">575.57.08</td>
<td>sunshine.pkg.tar.zst</td>
</tr>
</table>
@@ -80,15 +89,13 @@ According to AppImageLint the supported distro matrix of the AppImage is below.
- ✔ Debian bookworm
- ✔ Debian trixie
- ✔ Debian sid
- ✔ Ubuntu plucky
- ✔ Ubuntu noble
- ✔ Ubuntu jammy
- ✖ Ubuntu focal
- ✖ Ubuntu bionic
- ✖ Ubuntu xenial
- ✖ Ubuntu trusty
-Rocky Linux 8
- ✖ Rocky Linux 9
-CentOS 7
##### Install
1. Download [sunshine.AppImage](https://github.com/LizardByte/Sunshine/releases/latest/download/sunshine.AppImage)

View File

@@ -84,35 +84,9 @@ client only 1 Gbit/s or Wi-Fi. Similarly, a 1 Gbps host may be too fast for a
client having only a 100 Mbps interface.
As a workaround the transmission speed of the host NIC can be reduced: 1 Gbps
instead of 2.5 or 100 Mbps instead of 1 Gbps. A technically more advanced
instead of 2.5 or 100 Mbps instead of 1 Gbps. (A technically more advanced
solution would be to configure traffic shaping rules at the OS-level, so that
only Sunshine's traffic is slowed down.
Such a solution on Linux could look like that:
```bash
# 1) Remove existing qdisc (pfifo_fast)
sudo tc qdisc del dev <NIC> root
# 2) Add HTB root qdisc with default class 1:1
sudo tc qdisc add dev <NIC> root handle 1: htb default 1
# 3) Create class 1:1 for full 10 Gbit/s (all other traffic)
sudo tc class add dev <NIC> parent 1: classid 1:1 htb \
rate 10000mbit ceil 10000mbit burst 32k
# 4) Create class 1:10 for Sunshine game stream at 1 Gbit/s
sudo tc class add dev <NIC> parent 1: classid 1:10 htb \
rate 1000mbit ceil 1000mbit burst 32k
# 5) Filter UDP source port 47998 into class 1:10
sudo tc filter add dev <NIC> protocol ip parent 1: prio 1 \
u32 match ip protocol 17 0xff \
match ip sport 47998 0xffff flowid 1:10
```
In that way only the Sunshine traffic is limited by 1 Gbit. This is not persistent on reboots.
If you use a different port for the game stream you need to adjust the last command.
only Sunshine's traffic is slowed down.)
Sunshine versions > 0.23.1 include improved networking code that should
alleviate or even solve this issue (without reducing the NIC speed).

View File

@@ -9,8 +9,8 @@
},
"dependencies": {
"@lizardbyte/shared-web": "2025.626.181239",
"vue": "3.5.18",
"vue-i18n": "11.1.11"
"vue": "3.5.17",
"vue-i18n": "11.1.7"
},
"devDependencies": {
"@codecov/vite-plugin": "1.9.1",

View File

@@ -56,18 +56,18 @@ BuildRequires: which
BuildRequires: xorg-x11-server-Xvfb
# Conditional BuildRequires for cuda-gcc based on Fedora version
%if 0%{?fedora} <= 41
%if 0%{?fedora} >= 40 && 0%{?fedora} <= 41
BuildRequires: gcc13
BuildRequires: gcc13-c++
%global gcc_version 13
%global cuda_version 12.9.1
%global cuda_build 575.57.08
%global cuda_version 12.6.3
%global cuda_build 560.35.05
%elif %{?fedora} >= 42
BuildRequires: gcc14
BuildRequires: gcc14-c++
%global gcc_version 14
%global cuda_version 12.9.1
%global cuda_build 575.57.08
%global cuda_version 12.8.1
%global cuda_build 570.124.06
%endif
%global cuda_dir %{_builddir}/cuda
@@ -97,6 +97,9 @@ tar -xzf %{SOURCE0} -C %{_builddir}/Sunshine
# list directory
ls -a %{_builddir}/Sunshine
# patches
%autopatch -p1
%build
# exit on error
set -e
@@ -171,7 +174,7 @@ function install_cuda() {
--backup \
--directory="%{cuda_dir}" \
--verbose \
< "%{_builddir}/Sunshine/packaging/linux/patches/${architecture}/01-math_functions.patch"
< "%{_builddir}/Sunshine/packaging/linux/fedora/patches/f42/${architecture}/01-math_functions.patch"
fi
}

View File

@@ -32,12 +32,15 @@
"sources": [
{
"type": "git",
"url": "https://github.com/avahi/avahi.git",
"commit": "f060abee2807c943821d88839c013ce15db17b58",
"tag": "v0.8",
"url": "https://salsa.debian.org/utopia-team/avahi.git",
"commit": "1412c015d348166d58ea9c192239b00769eae24e",
"tag": "debian/0.8-13",
"x-checker-data": {
"type": "git",
"tag-pattern": "^v([\\d.]+)$"
"tag-pattern": "^debian\\/(\\d.+)$",
"versions": {
"<": "0.9"
}
}
},
{

View File

@@ -19,8 +19,8 @@
"only-arches": [
"x86_64"
],
"url": "https://developer.download.nvidia.com/compute/cuda/12.9.1/local_installers/cuda_12.9.1_575.57.08_linux.run",
"sha256": "0f6d806ddd87230d2adbe8a6006a9d20144fdbda9de2d6acc677daa5d036417a",
"url": "https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda_12.6.2_560.35.03_linux.run",
"sha256": "3729a89cb58f7ca6a46719cff110d6292aec7577585a8d71340f0dbac54fb237",
"dest-filename": "cuda.run"
},
{
@@ -28,8 +28,8 @@
"only-arches": [
"aarch64"
],
"url": "https://developer.download.nvidia.com/compute/cuda/12.9.1/local_installers/cuda_12.9.1_575.57.08_linux_sbsa.run",
"sha256": "64f47ab791a76b6889702425e0755385f5fa216c5a9f061875c7deed5f08cdb6",
"url": "https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda_12.6.2_560.35.03_linux_sbsa.run",
"sha256": "2249408848b705c18b9eadfb5161b52e4e36fcc5753647329cce93db141e5466",
"dest-filename": "cuda.run"
}
]

View File

@@ -5,24 +5,22 @@
"-Ddocumentation=disabled",
"-Dtests=disabled"
],
"cleanup": [
"/bin"
],
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libevdev.git",
"commit": "ac0056961c3332a260db063ab4fccc7747638a1d",
"tag": "libevdev-1.13.4",
"url": "https://salsa.debian.org/debian/libevdev.git",
"commit": "1aa7baa233d6df4cee6a66fbc61bb5ffc8b6e88d",
"tag": "debian/1.13.0+dfsg-1",
"x-checker-data": {
"type": "anitya",
"project-id": 20540,
"stable-only": true,
"tag-template": "libevdev-$version"
"type": "git",
"tag-pattern": "^debian\\/(\\d.\\d+\\.\\d+)",
"versions": {
"<": "1.13.1"
}
}
}
],
"cleanup": [
"/bin",
"/include",
"/lib/pkgconfig",
"/share"
]
}

View File

@@ -11,12 +11,15 @@
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libnotify.git",
"commit": "131aad01ff5f563b4863becbb6ed84dac6e75d5a",
"tag": "0.8.6",
"url": "https://salsa.debian.org/gnome-team/libnotify.git",
"commit": "ccf2f62ef0a4b264dd4eff32cab70a3e213ceb1a",
"tag": "debian/0.8.1-1",
"x-checker-data": {
"type": "git",
"tag-pattern": "^([\\d.]+)$"
"tag-pattern": "^debian\\/(\\d.+)$",
"versions": {
"<": "0.8.2"
}
}
}
]

View File

@@ -1,33 +1,25 @@
{
"name": "miniupnpc",
"buildsystem": "cmake-ninja",
"builddir": true,
"config-opts": [
"-DCMAKE_BUILD_TYPE=RelWithDebInfo",
"-DUPNPC_BUILD_STATIC=OFF",
"-DCMAKE_BUILD_TYPE=Release",
"-DUPNPC_BUILD_SAMPLE=OFF",
"-DUPNPC_BUILD_SHARED=ON",
"-DUPNPC_BUILD_TESTS=OFF",
"-DUPNPC_BUILD_SAMPLE=OFF"
"-DUPNPC_BUILD_TESTS=OFF"
],
"sources": [
{
"url": "https://miniupnp.tuxfamily.org/files/miniupnpc-2.3.3.tar.gz",
"sha256": "d52a0afa614ad6c088cc9ddff1ae7d29c8c595ac5fdd321170a05f41e634bd1a",
"type": "git",
"url": "https://salsa.debian.org/miniupnp-team/miniupnpc.git",
"commit": "c5fe3aa794e92a503cecec6a4071eb6d310b4e42",
"tag": "debian/2.2.4-1",
"x-checker-data": {
"type": "anitya",
"project-id": 1986,
"stable-only": true,
"url-template": "https://miniupnp.tuxfamily.org/files/miniupnpc-$version.tar.gz"
},
"type": "archive"
"type": "git",
"tag-pattern": "^debian\\/(\\d.+)$",
"versions": {
"<": "2.2.5"
}
}
}
],
"cleanup": [
"/share/man",
"/lib/pkgconfig",
"/lib/libminiupnpc.so",
"/lib/cmake",
"/include",
"/bin/external-ip.sh"
]
}

View File

@@ -1,24 +1,22 @@
{
"name": "numactl",
"buildsystem": "autotools",
"cleanup": [
"/bin"
],
"sources": [
{
"type": "git",
"url": "https://github.com/numactl/numactl.git",
"tag": "v2.0.19",
"commit": "3bc85e37d5a30da6790cb7e8bb488bb8f679170f",
"url": "https://salsa.debian.org/debian/numactl.git",
"commit": "640bb34497702f9aaeb8af1b491f32b91d03ec80",
"tag": "debian/2.0.16-1",
"x-checker-data": {
"type": "git",
"tag-pattern": "^v([\\d.]+)$"
"tag-pattern": "^debian\\/(\\d.+)$",
"versions": {
"<": "2.0.17"
}
}
}
],
"rm-configure": true,
"cleanup": [
"/include",
"/lib/pkgconfig",
"/lib/*.a",
"/lib/*.la",
"/lib/*.so",
"/share/man"
]
}

View File

@@ -2,12 +2,12 @@
# User Service
mkdir -p ~/.config/systemd/user
cp "/app/share/sunshine/systemd/user/sunshine.service" "$HOME/.config/systemd/user/sunshine.service"
echo "Sunshine User Service has been installed."
echo "Use [systemctl --user enable sunshine] once to autostart Sunshine on login."
cp /app/share/sunshine/systemd/user/sunshine.service $HOME/.config/systemd/user/sunshine.service
echo Sunshine User Service has been installed.
echo Use [systemctl --user enable sunshine] once to autostart Sunshine on login.
# Udev rule
UDEV=$(cat /app/share/sunshine/udev/rules.d/60-sunshine.rules)
echo "Configuring mouse permission."
echo Configuring mouse permission.
flatpak-spawn --host pkexec sh -c "echo '$UDEV' > /etc/udev/rules.d/60-sunshine.rules"
echo "Restart computer for mouse permission to take effect."
echo Restart computer for mouse permission to take effect.

View File

@@ -2,10 +2,10 @@
# User Service
systemctl --user stop sunshine
rm "$HOME/.config/systemd/user/sunshine.service"
rm $HOME/.config/systemd/user/sunshine.service
systemctl --user daemon-reload
echo "Sunshine User Service has been removed."
echo Sunshine User Service has been removed.
# Udev rule
flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/60-sunshine.rules"
echo "Input rules removed. Restart computer to take effect."
echo Input rules removed. Restart computer to take effect.

View File

@@ -29,21 +29,35 @@ class @PROJECT_NAME@ < Formula
depends_on "cmake" => :build
depends_on "doxygen" => :build
depends_on "graphviz" => :build
depends_on "ninja" => :build
depends_on "node" => :build
depends_on "pkgconf" => :build
depends_on "pkg-config" => :build
depends_on "curl"
depends_on "miniupnpc"
depends_on "openssl"
depends_on "opus"
depends_on "icu4c" => :recommended
on_macos do
depends_on xcode: ["15.3", :build]
end
on_linux do
# the "build" dependencies are for libayatana-appindicator
depends_on "at-spi2-core" => :build
depends_on "cairo" => :build
depends_on "fontconfig" => :build
depends_on "freetype" => :build
depends_on "fribidi" => :build
depends_on "gettext" => :build
depends_on "gobject-introspection" => :build
depends_on "graphite2" => :build
depends_on "gtk+3" => :build
depends_on "harfbuzz" => :build
depends_on "intltool" => :build
depends_on "libepoxy" => :build
depends_on "libxdamage" => :build
depends_on "libxkbcommon" => :build
depends_on "pango" => :build
depends_on "perl" => :build
depends_on "pixman" => :build
depends_on "avahi"
depends_on "libayatana-appindicator"
depends_on "libcap"
depends_on "libdrm"
depends_on "libnotify"
@@ -61,16 +75,128 @@ class @PROJECT_NAME@ < Formula
depends_on "pulseaudio"
depends_on "systemd"
depends_on "wayland"
end
fails_with :clang do
build 1400
cause "Requires C++23 support"
end
# resources that do not have brew packages
resource "libayatana-appindicator" do
url "https://github.com/AyatanaIndicators/libayatana-appindicator/archive/refs/tags/0.5.94.tar.gz"
sha256 "884a6bc77994c0b58c961613ca4c4b974dc91aa0f804e70e92f38a542d0d0f90"
end
fails_with :gcc do
version "12" # fails with GCC 12.x and earlier
cause "Requires C++23 support"
resource "libdbusmenu" do
url "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz"
sha256 "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a"
patch 'From 729546c51806a1b3ea6cb6efb7a115b1baa811f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Mon, 18 Nov 2019 19:58:53 +0100
Subject: [PATCH 1/1] Fix HAVE_VALGRIND AM_CONDITIONAL
The AM_CONDITIONAL should also be run with --disable-tests, otherwise
HAVE_VALGRIND is undefined.
---
configure | 4 ++--
configure.ac | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/configure b/configure
index 831a3bb..8913b9b 100644
--- a/configure
+++ b/configure
@@ -14801,6 +14801,8 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
have_valgrind=yes
+fi
+
fi
if test "x$have_valgrind" = "xyes"; then
HAVE_VALGRIND_TRUE=
@@ -14811,8 +14813,6 @@ else
fi
-fi
-
diff --git a/configure.ac b/configure.ac
index ace54d1..cbd38a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -120,8 +120,8 @@ PKG_CHECK_MODULES(DBUSMENUTESTS, json-glib-1.0 >= $JSON_GLIB_REQUIRED_VERSION
[have_tests=yes]
)
PKG_CHECK_MODULES(DBUSMENUTESTSVALGRIND, valgrind, have_valgrind=yes, have_valgrind=no)
-AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
])
+AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
AC_SUBST(DBUSMENUTESTS_CFLAGS)
AC_SUBST(DBUSMENUTESTS_LIBS)
--
2.46.2
'
end
resource "ayatana-ido" do
url "https://github.com/AyatanaIndicators/ayatana-ido/archive/refs/tags/0.10.4.tar.gz"
sha256 "bd59abd5f1314e411d0d55ce3643e91cef633271f58126be529de5fb71c5ab38"
patch 'From 8a09e6ad33c58c017c0c8fd756da036fc39428ea Mon Sep 17 00:00:00 2001
From: Alexander Koskovich <akoskovich@pm.me>
Date: Sun, 29 Sep 2024 13:47:54 -0400
Subject: [PATCH 1/1] Make introspection configurable
---
CMakeLists.txt | 1 +
src/CMakeLists.txt | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e13fcd..f3e9ec0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,7 @@ endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
option(ENABLE_TESTS "Enable all tests and checks" OFF)
option(ENABLE_COVERAGE "Enable coverage reports (includes enabling all tests and checks)" OFF)
option(ENABLE_WERROR "Treat all build warnings as errors" OFF)
+option(ENABLE_INTROSPECTION "Enable introspection" ON)
if(ENABLE_COVERAGE)
set(ENABLE_TESTS ON)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5b3638d..aca9481 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -108,6 +108,8 @@ install(TARGETS "ayatana-ido3-0.4" LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIB
# AyatanaIdo3-0.4.gir
+if (ENABLE_INTROSPECTION)
+
find_package(GObjectIntrospection REQUIRED QUIET)
if (INTROSPECTION_FOUND)
@@ -183,3 +185,5 @@ if (INTROSPECTION_FOUND)
endif ()
endif ()
+
+endif ()
--
2.46.2
'
end
resource "libayatana-indicator" do
url "https://github.com/AyatanaIndicators/libayatana-indicator/archive/refs/tags/0.9.4.tar.gz"
sha256 "a18d3c682e29afd77db24366f8475b26bda22b0e16ff569a2ec71cd6eb4eac95"
end
end
def install
@@ -80,7 +206,7 @@ class @PROJECT_NAME@ < Formula
args = %W[
-DBUILD_WERROR=ON
-DCMAKE_CXX_STANDARD=23
-DCMAKE_CXX_STANDARD=20
-DCMAKE_INSTALL_PREFIX=#{prefix}
-DHOMEBREW_ALLOW_FETCHCONTENT=ON
-DOPENSSL_ROOT_DIR=#{Formula["openssl"].opt_prefix}
@@ -122,6 +248,59 @@ class @PROJECT_NAME@ < Formula
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac?
# Handle system tray on Linux
if OS.linux?
# Build and install libayatana components
# Build libdbusmenu
resource("libdbusmenu").stage do
system "./configure",
"--prefix=#{prefix}",
"--with-gtk=3",
"--disable-dumper",
"--disable-static",
"--disable-tests",
"--disable-gtk-doc",
"--enable-introspection=no",
"--disable-vala"
system "make", "install"
end
# Build ayatana-ido
resource("ayatana-ido").stage do
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
"-DENABLE_INTROSPECTION=OFF",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
# Build libayatana-indicator
resource("libayatana-indicator").stage do
ENV.append_path "PKG_CONFIG_PATH", "#{lib}/pkgconfig"
ENV.append "LDFLAGS", "-L#{lib}"
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
# Build libayatana-appindicator
resource("libayatana-appindicator").stage do
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
"-DENABLE_BINDINGS_MONO=OFF",
"-DENABLE_BINDINGS_VALA=OFF",
"-DENABLE_GTKDOC=OFF",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
end
system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles",
*std_cmake_args,
*args

View File

@@ -1,63 +1,61 @@
#!/bin/bash
if ! [ -x "$(command -v ./go-png2ico)" ]; then
echo "./go-png2ico not found"
echo "download the executable from https://github.com/J-Siu/go-png2ico"
echo "and drop it in this folder"
exit 1
fi
if ! [ -x "$(command -v ./oxipng)" ]; then
echo "./oxipng executable not found"
echo "download the executable from https://github.com/shssoichiro/oxipng"
echo "and drop it in this folder"
exit 1
fi
if ! [ -x "$(command -v inkscape)" ]; then
echo "inkscape executable not found"
exit 1
fi
icon_base_sizes=(16 64)
icon_sizes_keys=() # associative array to prevent duplicates
icon_sizes_keys[256]=1
for icon_base_size in "${icon_base_sizes[@]}"; do
# increment in 25% till 400%
icon_size_increment=$((icon_base_size / 4))
for ((i = 0; i <= 12; i++)); do
icon_sizes_keys[icon_base_size + i * icon_size_increment]=1
done
done
# convert to normal array
icon_sizes=("${!icon_sizes_keys[@]}")
echo "using icon sizes:"
# shellcheck disable=SC2068 # intentionally word split
echo ${icon_sizes[@]}
src_vectors=("../../src_assets/common/assets/web/public/images/sunshine-locked.svg"
"../../src_assets/common/assets/web/public/images/sunshine-pausing.svg"
"../../src_assets/common/assets/web/public/images/sunshine-playing.svg"
"../../sunshine.svg")
echo "using sources vectors:"
# shellcheck disable=SC2068 # intentionally word split
echo ${src_vectors[@]}
for src_vector in "${src_vectors[@]}"; do
file_name=$(basename "${src_vector}" .svg)
png_files=()
for icon_size in "${icon_sizes[@]}"; do
png_file="${file_name}${icon_size}.png"
echo "converting ${png_file}"
inkscape -w "${icon_size}" -h "${icon_size}" "${src_vector}" --export-filename "${png_file}" &&
./oxipng -o max --strip safe --alpha "${png_file}" &&
png_files+=("${png_file}")
done
echo "packing ${file_name}.ico"
./go-png2ico "${png_files[@]}" "${file_name}.ico"
done
#!/bin/bash
if ! [ -x "$(command -v ./go-png2ico)" ]; then
echo "./go-png2ico not found"
echo "download the executable from https://github.com/J-Siu/go-png2ico"
echo "and drop it in this folder"
exit 1
fi
if ! [ -x "$(command -v ./oxipng)" ]; then
echo "./oxipng executable not found"
echo "download the executable from https://github.com/shssoichiro/oxipng"
echo "and drop it in this folder"
exit 1
fi
if ! [ -x "$(command -v inkscape)" ]; then
echo "inkscape executable not found"
exit 1
fi
icon_base_sizes=(16 64)
icon_sizes_keys=() # associative array to prevent duplicates
icon_sizes_keys[256]=1
for icon_base_size in ${icon_base_sizes[@]}; do
# increment in 25% till 400%
icon_size_increment=$((icon_base_size / 4))
for ((i = 0; i <= 12; i++)); do
icon_sizes_keys[$((icon_base_size + i * icon_size_increment))]=1
done
done
# convert to normal array
icon_sizes=${!icon_sizes_keys[@]}
echo "using icon sizes:"
echo ${icon_sizes[@]}
src_vectors=("../../src_assets/common/assets/web/public/images/sunshine-locked.svg"
"../../src_assets/common/assets/web/public/images/sunshine-pausing.svg"
"../../src_assets/common/assets/web/public/images/sunshine-playing.svg"
"../../sunshine.svg")
echo "using sources vectors:"
echo ${src_vectors[@]}
for src_vector in ${src_vectors[@]}; do
file_name=`basename "$src_vector" .svg`
png_files=()
for icon_size in ${icon_sizes[@]}; do
png_file="${file_name}${icon_size}.png"
echo "converting ${png_file}"
inkscape -w $icon_size -h $icon_size "$src_vector" --export-filename "${png_file}" &&
./oxipng -o max --strip safe --alpha "${png_file}" &&
png_files+=("${png_file}")
done
echo "packing ${file_name}.ico"
./go-png2ico "${png_files[@]}" "${file_name}.ico"
done

View File

@@ -3,7 +3,6 @@ set -e
# Default value for arguments
appimage_build=0
cuda_patches=0
num_processors=$(nproc)
publisher_name="Third Party Publisher"
publisher_website=""
@@ -29,7 +28,6 @@ Options:
-h, --help Display this help message.
-s, --sudo-off Disable sudo command.
--appimage-build Compile for AppImage, this will not create the AppImage, just the executable.
--cuda-patches Apply cuda patches.
--num-processors The number of processors to use for compilation. Default is the value of 'nproc'.
--publisher-name The name of the publisher (not developer) of the application.
--publisher-website The URL of the publisher's website.
@@ -57,9 +55,6 @@ while getopts ":hs-:" opt; do
appimage_build=1
skip_libva=1
;;
cuda-patches)
cuda_patches=1
;;
num-processors=*)
num_processors="${OPTARG#*=}"
;;
@@ -101,11 +96,9 @@ function add_arch_deps() {
'base-devel'
'cmake'
'curl'
'doxygen'
"gcc${gcc_version}"
"gcc${gcc_version}-libs"
'git'
'graphviz'
'libayatana-appindicator'
'libcap'
'libdrm'
@@ -190,15 +183,7 @@ function add_debian_based_deps() {
fi
}
function add_test_ppa() {
if [ "$ubuntu_test_repo" == 1 ]; then
$package_install_command "software-properties-common"
${sudo_cmd} add-apt-repository ppa:ubuntu-toolchain-r/test -y
fi
}
function add_debian_deps() {
add_test_ppa
add_debian_based_deps
dependencies+=(
"libayatana-appindicator3-dev"
@@ -206,7 +191,11 @@ function add_debian_deps() {
}
function add_ubuntu_deps() {
add_test_ppa
if [ "$ubuntu_test_repo" == 1 ]; then
# allow newer gcc
${sudo_cmd} add-apt-repository ppa:ubuntu-toolchain-r/test -y
fi
add_debian_based_deps
dependencies+=(
"libappindicator3-dev"
@@ -307,24 +296,6 @@ function install_cuda() {
"${build_dir}/cuda.run" --silent --toolkit --toolkitpath="${build_dir}/cuda" --no-opengl-libs --no-man-page --no-drm
rm "${build_dir}/cuda.run"
nvcc_path="${build_dir}/cuda/bin/nvcc"
# run cuda patches
if [ "$cuda_patches" == 1 ]; then
echo "Applying CUDA patches"
local patch_dir="${script_dir}/../packaging/linux/patches/${architecture}"
if [ -d "$patch_dir" ]; then
for patch in "$patch_dir"/*.patch; do
echo "Applying patch: $patch"
patch -p2 \
--backup \
--directory="${build_dir}/cuda" \
--verbose \
< "$patch"
done
else
echo "No patches found for architecture: $architecture"
fi
fi
}
function check_version() {
@@ -429,7 +400,7 @@ function run_install() {
for file in "${gcc_alternative_files[@]}"; do
file_path="/etc/alternatives/$file"
if [ -e "$file_path" ]; then
${sudo_cmd} mv "$file_path" "$file_path.bak"
mv "$file_path" "$file_path.bak"
fi
done
@@ -468,14 +439,12 @@ function run_install() {
echo "Compiling doxygen"
doxygen_url="https://github.com/doxygen/doxygen/releases/download/Release_${_doxygen_min}/doxygen-${doxygen_min}.src.tar.gz"
echo "doxygen url: ${doxygen_url}"
pushd "${build_dir}"
wget "$doxygen_url" --progress=bar:force:noscroll -q --show-progress -O "doxygen.tar.gz"
tar -xzf "doxygen.tar.gz"
cd "doxygen-${doxygen_min}"
cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="."
ninja -C "build" -j"${num_processors}"
${sudo_cmd} ninja -C "build" install
popd
wget "$doxygen_url" --progress=bar:force:noscroll -q --show-progress -O "${build_dir}/doxygen.tar.gz"
tar -xzf "${build_dir}/doxygen.tar.gz"
cd "doxygen-${doxygen_min}"
cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="."
ninja -C "build" -j"${num_processors}"
ninja -C "build" install
else
echo "Doxygen version not in range, skipping docs"
cmake_args+=("-DBUILD_DOCS=OFF")
@@ -487,8 +456,6 @@ function run_install() {
nvm_url="https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh"
echo "nvm url: ${nvm_url}"
wget -qO- ${nvm_url} | bash
# shellcheck source=/dev/null # we don't care that shellcheck cannot find nvm.sh
source "$HOME/.nvm/nvm.sh"
nvm install node
nvm use node
@@ -563,26 +530,27 @@ elif grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then
version="12"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
cuda_version="12.0.0"
cuda_build="525.60.13"
gcc_version="12"
nvm_node=0
elif grep -q "PLATFORM_ID=\"platform:f40\"" /etc/os-release; then
distro="fedora"
version="40"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version=12.6.3
cuda_build=560.35.05
gcc_version="13"
nvm_node=0
elif grep -q "Debian GNU/Linux 13 (trixie)" /etc/os-release; then
distro="debian"
version="13"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
gcc_version="14"
nvm_node=0
dev_tools_group="Development Tools"
elif grep -q "PLATFORM_ID=\"platform:f41\"" /etc/os-release; then
distro="fedora"
version="41"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
cuda_version=12.6.3
cuda_build=560.35.05
gcc_version="13"
nvm_node=0
dev_tools_group="development-tools"
@@ -591,8 +559,8 @@ elif grep -q "PLATFORM_ID=\"platform:f42\"" /etc/os-release; then
version="42"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
cuda_version=12.8.1
cuda_build=570.124.06
gcc_version="14"
nvm_node=0
dev_tools_group="development-tools"
@@ -601,27 +569,27 @@ elif grep -q "Ubuntu 22.04" /etc/os-release; then
version="22.04"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
gcc_version="13"
cuda_version="11.8.0"
cuda_build="520.61.05"
gcc_version="11"
nvm_node=1
elif grep -q "Ubuntu 24.04" /etc/os-release; then
distro="ubuntu"
version="24.04"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
gcc_version="14"
cuda_version="11.8.0"
cuda_build="520.61.05"
gcc_version="11"
nvm_node=0
elif grep -q "Ubuntu 25.04" /etc/os-release; then
distro="ubuntu"
version="25.04"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="12.9.1"
cuda_build="575.57.08"
gcc_version="14"
cuda_version="11.8.0"
cuda_build="520.61.05"
gcc_version="11"
nvm_node=0
else
echo "Unsupported Distro or Version"

View File

@@ -32,7 +32,7 @@
#include <shellapi.h>
#endif
#if !defined(__ANDROID__) && !defined(__APPLE__)
#ifndef __APPLE__
// For NVENC legacy constants
#include <ffnvcodec/nvEncodeAPI.h>
#endif
@@ -504,8 +504,7 @@ namespace config {
{} // wa
}, // display_device
0, // max_bitrate
0 // minimum_fps_target (0 = framerate)
0 // max_bitrate
};
audio_t audio {
@@ -1039,12 +1038,9 @@ namespace config {
}
void apply_config(std::unordered_map<std::string, std::string> &&vars) {
#ifndef __ANDROID__
// TODO: Android can possibly support this
if (!fs::exists(stream.file_apps.c_str())) {
fs::copy_file(SUNSHINE_ASSETS_DIR "/apps.json", stream.file_apps);
}
#endif
for (auto &[name, val] : vars) {
BOOST_LOG(info) << "config: '"sv << name << "' = "sv << val;
@@ -1070,7 +1066,7 @@ namespace config {
bool_f(vars, "nvenc_opengl_vulkan_on_dxgi", video.nv_opengl_vulkan_on_dxgi);
bool_f(vars, "nvenc_latency_over_power", video.nv_sunshine_high_power_mode);
#if !defined(__ANDROID__) && !defined(__APPLE__)
#ifndef __APPLE__
video.nv_legacy.preset = video.nv.quality_preset + 11;
video.nv_legacy.multipass = video.nv.two_pass == nvenc::nvenc_two_pass::quarter_resolution ? NV_ENC_TWO_PASS_QUARTER_RESOLUTION :
video.nv.two_pass == nvenc::nvenc_two_pass::full_resolution ? NV_ENC_TWO_PASS_FULL_RESOLUTION :
@@ -1147,7 +1143,6 @@ namespace config {
}
int_f(vars, "max_bitrate", video.max_bitrate);
double_between_f(vars, "minimum_fps_target", video.minimum_fps_target, {0.0, 1000.0});
path_f(vars, "pkey", nvhttp.pkey);
path_f(vars, "cert", nvhttp.cert);
@@ -1421,7 +1416,7 @@ namespace config {
if (!service_ctrl::is_service_running()) {
// If the service isn't running, relaunch ourselves as admin to start it
WCHAR executable[MAX_PATH];
GetModuleFileNameW(nullptr, executable, ARRAYSIZE(executable));
GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable));
SHELLEXECUTEINFOW shell_exec_info {};
shell_exec_info.cbSize = sizeof(shell_exec_info);

View File

@@ -141,7 +141,6 @@ namespace config {
} dd;
int max_bitrate; // Maximum bitrate, sets ceiling in kbps for bitrate requested from client
double minimum_fps_target; ///< Lowest framerate that will be used when streaming. Range 0-1000, 0 = half of client's requested framerate.
};
struct audio_t {

View File

@@ -8,7 +8,6 @@
// standard includes
#include <filesystem>
#include <format>
#include <fstream>
#include <set>
@@ -693,8 +692,9 @@ namespace confighttp {
* @api_examples{/api/apps/9999| DELETE| null}
*/
void deleteApp(resp_https_t response, req_https_t request) {
// Skip check_content_type() for this endpoint since the request body is not used.
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -714,7 +714,7 @@ namespace confighttp {
if (const int max_index = static_cast<int>(apps_node.size()) - 1; max_index < 0) {
error = "No applications to delete";
} else {
error = std::format("'index' {} out of range, max index is {}", index, max_index);
error = "'index' out of range, max index is "s + std::to_string(max_index);
}
bad_request(response, request, error);
return;
@@ -731,7 +731,7 @@ namespace confighttp {
proc::refresh(config::stream.file_apps);
output_tree["status"] = true;
output_tree["result"] = std::format("application {} deleted", index);
output_tree["result"] = "application " + std::to_string(index) + " deleted";
send_response(response, output_tree);
} catch (std::exception &e) {
BOOST_LOG(warning) << "DeleteApp: "sv << e.what();

View File

@@ -4,7 +4,6 @@
*/
// standard includes
#include <csignal>
#include <format>
#include <iostream>
#include <thread>
@@ -26,11 +25,13 @@ extern "C" {
using namespace std::literals;
void launch_ui(const std::optional<std::string> &path) {
std::string url = std::format("https://localhost:{}", static_cast<int>(net::map_port(confighttp::PORT_HTTPS)));
if (path) {
url += *path;
}
void launch_ui() {
std::string url = "https://localhost:" + std::to_string(net::map_port(confighttp::PORT_HTTPS));
platf::open_url(url);
}
void launch_ui_with_path(std::string path) {
std::string url = "https://localhost:" + std::to_string(net::map_port(confighttp::PORT_HTTPS)) + path;
platf::open_url(url);
}
@@ -191,8 +192,8 @@ namespace service_ctrl {
}
private:
SC_HANDLE scm_handle = nullptr;
SC_HANDLE service_handle = nullptr;
SC_HANDLE scm_handle = NULL;
SC_HANDLE service_handle = NULL;
};
bool is_service_running() {

View File

@@ -14,13 +14,19 @@
/**
* @brief Launch the Web UI.
* @param path Optional path to append to the base URL.
* @examples
* launch_ui();
* launch_ui("/pin");
* @examples_end
*/
void launch_ui(const std::optional<std::string> &path = std::nullopt);
void launch_ui();
/**
* @brief Launch the Web UI at a specific endpoint.
* @examples
* launch_ui_with_path("/pin");
* @examples_end
*/
void launch_ui_with_path(std::string path);
/**
* @brief Functions for handling command line arguments.

View File

@@ -15,17 +15,11 @@
#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <display_device/logging.h>
// local includes
#include "logging.h"
// conditional includes
#ifdef __ANDROID__
#include <android/log.h>
#else
#include <display_device/logging.h>
#endif
extern "C" {
#include <libavutil/log.h>
}
@@ -103,48 +97,6 @@ namespace logging {
os << "["sv << std::put_time(&lt, "%Y-%m-%d %H:%M:%S.") << boost::format("%03u") % ms.count() << "]: "sv
<< log_type << view.attribute_values()[message].extract<std::string>();
}
#ifdef __ANDROID__
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
void android_log(const std::string &message, int severity) {
android_LogPriority android_priority;
switch (severity) {
case 0:
android_priority = ANDROID_LOG_VERBOSE;
break;
case 1:
android_priority = ANDROID_LOG_DEBUG;
break;
case 2:
android_priority = ANDROID_LOG_INFO;
break;
case 3:
android_priority = ANDROID_LOG_WARN;
break;
case 4:
android_priority = ANDROID_LOG_ERROR;
break;
case 5:
android_priority = ANDROID_LOG_FATAL;
break;
default:
android_priority = ANDROID_LOG_UNKNOWN;
break;
}
__android_log_print(android_priority, "Sunshine", "%s", message.c_str());
}
// custom sink backend for android
struct android_sink_backend: public sinks::basic_sink_backend<sinks::concurrent_feeding> {
void consume(const bl::record_view &rec) {
int log_sev = rec[severity].get();
const std::string log_msg = rec[expr::smessage].get();
// log to android
android_log(log_msg, log_sev);
}
};
#endif
[[nodiscard]] std::unique_ptr<deinit_t> init(int min_log_level, const std::string &log_file) {
if (sink) {
@@ -152,10 +104,8 @@ namespace logging {
deinit();
}
#ifndef __ANDROID__
setup_av_logging(min_log_level);
setup_libdisplaydevice_logging(min_log_level);
#endif
sink = boost::make_shared<text_sink>();
@@ -163,7 +113,6 @@ namespace logging {
boost::shared_ptr<std::ostream> stream {&std::cout, boost::null_deleter()};
sink->locked_backend()->add_stream(stream);
#endif
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>(log_file));
sink->set_filter(severity >= min_log_level);
sink->set_formatter(&formatter);
@@ -173,15 +122,9 @@ namespace logging {
sink->locked_backend()->auto_flush(true);
bl::core::get()->add_sink(sink);
#ifdef __ANDROID__
auto android_sink = boost::make_shared<sinks::synchronous_sink<android_sink_backend>>();
bl::core::get()->add_sink(android_sink);
#endif
return std::make_unique<deinit_t>();
}
#ifndef __ANDROID__
void setup_av_logging(int min_log_level) {
if (min_log_level >= 1) {
av_log_set_level(AV_LOG_QUIET);
@@ -239,7 +182,6 @@ namespace logging {
}
});
}
#endif
void log_flush() {
if (sink) {

View File

@@ -186,7 +186,7 @@ int main(int argc, char *argv[]) {
wnd_class.lpszClassName = "SunshineSessionMonitorClass";
wnd_class.lpfnWndProc = SessionMonitorWindowProc;
if (!RegisterClassA(&wnd_class)) {
session_monitor_hwnd_promise.set_value(nullptr);
session_monitor_hwnd_promise.set_value(NULL);
BOOST_LOG(error) << "Failed to register session monitor window class"sv << std::endl;
return;
}
@@ -340,7 +340,6 @@ int main(int argc, char *argv[]) {
std::thread httpThread {nvhttp::start};
std::thread configThread {confighttp::start};
std::thread rtspThread {rtsp_stream::start};
#ifdef _WIN32
// If we're using the default port and GameStream is enabled, warn the user
@@ -350,12 +349,10 @@ int main(int argc, char *argv[]) {
}
#endif
// Wait for shutdown
shutdown_event->view();
rtsp_stream::rtpThread();
httpThread.join();
configThread.join();
rtspThread.join();
task_pool.stop();
task_pool.join();

View File

@@ -5,9 +5,6 @@
// this include
#include "nvenc_base.h"
// standard includes
#include <format>
// local includes
#include "src/config.h"
#include "src/logging.h"
@@ -430,7 +427,7 @@ namespace nvenc {
extra += " two-pass";
}
if (config.vbv_percentage_increase > 0 && get_encoder_cap(NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE)) {
extra += std::format(" vbv+{}", config.vbv_percentage_increase);
extra += " vbv+" + std::to_string(config.vbv_percentage_increase);
}
if (encoder_params.rfi) {
extra += " rfi";
@@ -442,7 +439,7 @@ namespace nvenc {
extra += " spatial-aq";
}
if (enc_config.rcParams.enableMinQP) {
extra += std::format(" qpmin={}", enc_config.rcParams.minQP.qpInterP);
extra += " qpmin=" + std::to_string(enc_config.rcParams.minQP.qpInterP);
}
if (config.insert_filler_data) {
extra += " filler-data";

View File

@@ -12,13 +12,13 @@ namespace nvenc {
nvenc_d3d11::nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type):
nvenc_base(device_type) {
async_event_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
async_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
}
nvenc_d3d11::~nvenc_d3d11() {
if (dll) {
FreeLibrary(dll);
dll = nullptr;
dll = NULL;
}
if (async_event_handle) {
CloseHandle(async_event_handle);
@@ -36,7 +36,7 @@ namespace nvenc {
constexpr auto dll_name = "nvEncodeAPI.dll";
#endif
if ((dll = LoadLibraryEx(dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
if ((dll = LoadLibraryEx(dll_name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
if (auto create_instance = (decltype(NvEncodeAPICreateInstance) *) GetProcAddress(dll, "NvEncodeAPICreateInstance")) {
auto new_nvenc = std::make_unique<NV_ENCODE_API_FUNCTION_LIST>();
new_nvenc->version = min_struct_version(NV_ENCODE_API_FUNCTION_LIST_VER);
@@ -55,7 +55,7 @@ namespace nvenc {
if (dll) {
FreeLibrary(dll);
dll = nullptr;
dll = NULL;
}
return false;

View File

@@ -39,7 +39,7 @@ namespace nvenc {
bool wait_for_async_event(uint32_t timeout_ms) override;
private:
HMODULE dll = nullptr;
HMODULE dll = NULL;
};
} // namespace nvenc

View File

@@ -63,7 +63,7 @@ namespace nvenc {
constexpr auto dll_name = "nvcuda.dll";
if ((cuda_functions.dll = LoadLibraryEx(dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
if ((cuda_functions.dll = LoadLibraryEx(dll_name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
auto load_function = [&]<typename T>(T &location, auto symbol) -> bool {
location = (T) GetProcAddress(cuda_functions.dll, symbol);
return location != nullptr;

View File

@@ -56,7 +56,7 @@ namespace nvenc {
autopop_context push_context();
HMODULE dll = nullptr;
HMODULE dll = NULL;
const ID3D11DevicePtr d3d_device;
ID3D11Texture2DPtr d3d_input_texture;

View File

@@ -7,7 +7,6 @@
// standard includes
#include <filesystem>
#include <format>
#include <string>
#include <utility>
@@ -155,7 +154,7 @@ namespace nvhttp {
std::string get_arg(const args_t &args, const char *name, const char *default_value = nullptr) {
auto it = args.find(name);
if (it == std::end(args)) {
if (default_value != nullptr) {
if (default_value != NULL) {
return std::string(default_value);
}
@@ -637,7 +636,7 @@ namespace nvhttp {
tree.put("root.<xmlattr>.status_code", 400);
tree.put(
"root.<xmlattr>.status_message",
std::format("Pin must be 4 digits, {} provided", pin.size())
"Pin must be 4 digits, " + std::to_string(pin.size()) + " provided"
);
return false;
}
@@ -897,15 +896,7 @@ namespace nvhttp {
}
tree.put("root.<xmlattr>.status_code", 200);
tree.put(
"root.sessionUrl0",
std::format(
"{}{}:{}",
launch_session->rtsp_url_scheme,
net::addr_to_url_escaped_string(request->local_endpoint().address()),
static_cast<int>(net::map_port(rtsp_stream::RTSP_SETUP_PORT))
)
);
tree.put("root.sessionUrl0", launch_session->rtsp_url_scheme + net::addr_to_url_escaped_string(request->local_endpoint().address()) + ':' + std::to_string(net::map_port(rtsp_stream::RTSP_SETUP_PORT)));
tree.put("root.gamesession", 1);
rtsp_stream::launch_session_raise(launch_session);
@@ -987,15 +978,7 @@ namespace nvhttp {
}
tree.put("root.<xmlattr>.status_code", 200);
tree.put(
"root.sessionUrl0",
std::format(
"{}{}:{}",
launch_session->rtsp_url_scheme,
net::addr_to_url_escaped_string(request->local_endpoint().address()),
static_cast<int>(net::map_port(rtsp_stream::RTSP_SETUP_PORT))
)
);
tree.put("root.sessionUrl0", launch_session->rtsp_url_scheme + net::addr_to_url_escaped_string(request->local_endpoint().address()) + ':' + std::to_string(net::map_port(rtsp_stream::RTSP_SETUP_PORT)));
tree.put("root.resume", 1);
rtsp_stream::launch_session_raise(launch_session);

View File

@@ -424,7 +424,7 @@ namespace platf {
// UDP GSO on Linux currently only supports sending 64K or 64 segments at a time
size_t seg_index = 0;
const size_t seg_max = 65536 / 1500;
struct iovec iovs[(send_info.headers ? std::min(seg_max, send_info.block_count) : 1) * max_iovs_per_msg];
struct iovec iovs[(send_info.headers ? std::min(seg_max, send_info.block_count) : 1) * max_iovs_per_msg] = {};
auto msg_size = send_info.header_size + send_info.payload_size;
while (seg_index < send_info.block_count) {
int iovlen = 0;
@@ -507,11 +507,10 @@ namespace platf {
{
// If GSO is not supported, use sendmmsg() instead.
struct mmsghdr msgs[send_info.block_count];
struct iovec iovs[send_info.block_count * (send_info.headers ? 2 : 1)];
struct mmsghdr msgs[send_info.block_count] = {};
struct iovec iovs[send_info.block_count * (send_info.headers ? 2 : 1)] = {};
int iov_idx = 0;
for (size_t i = 0; i < send_info.block_count; i++) {
msgs[i].msg_len = 0;
msgs[i].msg_hdr.msg_iov = &iovs[iov_idx];
msgs[i].msg_hdr.msg_iovlen = send_info.headers ? 2 : 1;
@@ -529,7 +528,6 @@ namespace platf {
msgs[i].msg_hdr.msg_namelen = msg.msg_namelen;
msgs[i].msg_hdr.msg_control = cmbuf.buf;
msgs[i].msg_hdr.msg_controllen = cmbuflen;
msgs[i].msg_hdr.msg_flags = 0;
}
// Call sendmmsg() until all messages are sent
@@ -622,7 +620,7 @@ namespace platf {
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
}
struct iovec iovs[2];
struct iovec iovs[2] = {};
int iovlen = 0;
if (send_info.header) {
iovs[iovlen].iov_base = (void *) send_info.header;

View File

@@ -4,7 +4,6 @@
*/
// standard includes
#include <fcntl.h>
#include <format>
#include <sstream>
#include <string>
@@ -575,7 +574,7 @@ namespace va {
if (!display) {
char string[1024];
auto bytes = readlink(std::format("/proc/self/fd/{}", fd).c_str(), string, sizeof(string));
auto bytes = readlink(("/proc/self/fd/" + std::to_string(fd)).c_str(), string, sizeof(string));
std::string_view render_device {string, (std::size_t) bytes};

View File

@@ -4,11 +4,8 @@
*/
#define INITGUID
// standard includes
#include <format>
// platform includes
#include <Audioclient.h>
#include <audioclient.h>
#include <avrt.h>
#include <mmdeviceapi.h>
#include <newdev.h>
@@ -171,27 +168,28 @@ namespace {
waveformat.SubFormat == KSDATAFORMAT_SUBTYPE_PCM ? "S" :
"UNKNOWN";
result += std::format("{} {} ", static_cast<int>(waveformat.Samples.wValidBitsPerSample), static_cast<int>(waveformat.Format.nSamplesPerSec));
result += std::to_string(waveformat.Samples.wValidBitsPerSample) + " " +
std::to_string(waveformat.Format.nSamplesPerSec) + " ";
switch (waveformat.dwChannelMask) {
case waveformat_mask_stereo:
case (waveformat_mask_stereo):
result += "2.0";
break;
case waveformat_mask_surround51_with_backspeakers:
case (waveformat_mask_surround51_with_backspeakers):
result += "5.1";
break;
case waveformat_mask_surround51_with_sidespeakers:
case (waveformat_mask_surround51_with_sidespeakers):
result += "5.1 (sidespeakers)";
break;
case waveformat_mask_surround71:
case (waveformat_mask_surround71):
result += "7.1";
break;
default:
result += std::format("{} channels (unrecognized)", static_cast<int>(waveformat.Format.nChannels));
result += std::to_string(waveformat.Format.nChannels) + " channels (unrecognized)";
break;
}
@@ -377,7 +375,7 @@ namespace platf::audio {
*ppvInterface = (IMMNotificationClient *) this;
return S_OK;
} else {
*ppvInterface = nullptr;
*ppvInterface = NULL;
return E_NOINTERFACE;
}
}
@@ -679,7 +677,7 @@ namespace platf::audio {
float *sample_buf_pos;
int channels;
HANDLE mmcss_task_handle = nullptr;
HANDLE mmcss_task_handle = NULL;
};
class audio_control_t: public ::platf::audio_control_t {

View File

@@ -12,7 +12,7 @@
#include <dxgi.h>
#include <dxgi1_6.h>
#include <Unknwn.h>
#include <winrt/windows.graphics.capture.h>
#include <winrt/Windows.Graphics.Capture.h>
// local includes
#include "src/platform/common.h"

View File

@@ -601,12 +601,12 @@ namespace platf::dxgi {
LUID val;
if (OpenProcessToken(GetCurrentProcess(), flags, &token) &&
!!LookupPrivilegeValue(nullptr, SE_INC_BASE_PRIORITY_NAME, &val)) {
!!LookupPrivilegeValue(NULL, SE_INC_BASE_PRIORITY_NAME, &val)) {
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = val;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), nullptr, nullptr)) {
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL)) {
BOOST_LOG(warning) << "Could not set privilege to increase GPU priority";
}
}
@@ -918,20 +918,20 @@ namespace platf::dxgi {
"DXGI_FORMAT_A8P8",
"DXGI_FORMAT_B4G4R4A4_UNORM",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"DXGI_FORMAT_P208",
"DXGI_FORMAT_V208",

View File

@@ -7,7 +7,7 @@
// platform includes
#include <d3dcompiler.h>
#include <DirectXMath.h>
#include <directxmath.h>
extern "C" {
#include <libavcodec/avcodec.h>
@@ -1739,7 +1739,7 @@ namespace platf::dxgi {
img->data = nullptr;
if (img->encoder_texture_handle) {
CloseHandle(img->encoder_texture_handle);
img->encoder_texture_handle = nullptr;
img->encoder_texture_handle = NULL;
}
// Initialize format-dependent fields

View File

@@ -13,7 +13,7 @@
// Gross hack to work around MINGW-packages#22160
#define ____FIReference_1_boolean_INTERFACE_DEFINED__
#include <Windows.Graphics.Capture.Interop.h>
#include <windows.graphics.capture.interop.h>
#include <winrt/windows.foundation.h>
#include <winrt/windows.foundation.metadata.h>
#include <winrt/windows.graphics.directx.direct3d11.h>

View File

@@ -5,7 +5,7 @@
#define WINVER 0x0A00
// platform includes
#include <Windows.h>
#include <windows.h>
// standard includes
#include <cmath>
@@ -293,7 +293,7 @@ namespace platf {
if (gamepad.repeat_task) {
task_pool.cancel(gamepad.repeat_task);
gamepad.repeat_task = nullptr;
gamepad.repeat_task = 0;
}
if (gamepad.gp && vigem_target_is_attached(gamepad.gp.get())) {
@@ -1452,7 +1452,7 @@ namespace platf {
// Cancel any pending updates. We will requeue one here when we're finished.
if (gamepad.repeat_task) {
task_pool.cancel(gamepad.repeat_task);
gamepad.repeat_task = nullptr;
gamepad.repeat_task = 0;
}
if (gamepad.gp && vigem_target_is_attached(gamepad.gp.get())) {
@@ -1598,8 +1598,8 @@ namespace platf {
uint16_t y = touch.y * 943;
uint8_t touchData[] = {
(uint8_t) (x & 0xFF), // Low 8 bits of X
(uint8_t) ((x >> 8 & 0x0F) | (y & 0x0F) << 4), // High 4 bits of X and low 4 bits of Y
(uint8_t) (y >> 4 & 0xFF) // High 8 bits of Y
(uint8_t) (((x >> 8) & 0x0F) | ((y & 0x0F) << 4)), // High 4 bits of X and low 4 bits of Y
(uint8_t) (((y >> 4) & 0xFF)) // High 8 bits of Y
};
report.sCurrentTouch.bPacketCounter++;

View File

@@ -22,13 +22,13 @@
#include <iphlpapi.h>
#include <iterator>
#include <timeapi.h>
#include <UserEnv.h>
#include <WinSock2.h>
#include <Windows.h>
#include <WinUser.h>
#include <userenv.h>
#include <winsock2.h>
#include <windows.h>
#include <winuser.h>
#include <wlanapi.h>
#include <WS2tcpip.h>
#include <WtsApi32.h>
#include <ws2tcpip.h>
#include <wtsapi32.h>
#include <sddl.h>
// clang-format on
@@ -117,7 +117,7 @@ namespace platf {
std::filesystem::path appdata() {
WCHAR sunshine_path[MAX_PATH];
GetModuleFileNameW(nullptr, sunshine_path, _countof(sunshine_path));
GetModuleFileNameW(NULL, sunshine_path, _countof(sunshine_path));
return std::filesystem::path {sunshine_path}.remove_filename() / L"config"sv;
}
@@ -410,16 +410,16 @@ namespace platf {
LPPROC_THREAD_ATTRIBUTE_LIST allocate_proc_thread_attr_list(DWORD attribute_count) {
SIZE_T size;
InitializeProcThreadAttributeList(nullptr, attribute_count, 0, &size);
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
auto list = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(GetProcessHeap(), 0, size);
if (list == nullptr) {
return nullptr;
if (list == NULL) {
return NULL;
}
if (!InitializeProcThreadAttributeList(list, attribute_count, 0, &size)) {
HeapFree(GetProcessHeap(), 0, list);
return nullptr;
return NULL;
}
return list;
@@ -518,7 +518,7 @@ namespace platf {
// Allocate a process attribute list with space for 2 elements
startup_info.lpAttributeList = allocate_proc_thread_attr_list(2);
if (startup_info.lpAttributeList == nullptr) {
if (startup_info.lpAttributeList == NULL) {
// If the allocation failed, set ec to an appropriate error code and return the structure
ec = std::make_error_code(std::errc::not_enough_memory);
return startup_info;
@@ -530,7 +530,7 @@ namespace platf {
// Populate std handles if the caller gave us a log file to use
startup_info.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
startup_info.StartupInfo.hStdInput = nullptr;
startup_info.StartupInfo.hStdInput = NULL;
startup_info.StartupInfo.hStdOutput = log_file_handle;
startup_info.StartupInfo.hStdError = log_file_handle;
@@ -539,7 +539,7 @@ namespace platf {
//
// Note: The value we point to here must be valid for the lifetime of the attribute list,
// so we need to point into the STARTUPINFO instead of our log_file_variable on the stack.
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &startup_info.StartupInfo.hStdOutput, sizeof(startup_info.StartupInfo.hStdOutput), nullptr, nullptr);
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &startup_info.StartupInfo.hStdOutput, sizeof(startup_info.StartupInfo.hStdOutput), NULL, NULL);
}
if (job) {
@@ -547,7 +547,7 @@ namespace platf {
//
// Note: The value we point to here must be valid for the lifetime of the attribute list,
// so we take a HANDLE* instead of just a HANDLE to use the caller's stack storage.
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, job, sizeof(*job), nullptr, nullptr);
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, job, sizeof(*job), NULL, NULL);
}
return startup_info;
@@ -555,11 +555,11 @@ namespace platf {
/**
* @brief This function overrides HKEY_CURRENT_USER and HKEY_CLASSES_ROOT using the provided token.
* @param token The primary token identifying the user to use, or `nullptr` to restore original keys.
* @param token The primary token identifying the user to use, or `NULL` to restore original keys.
* @return `true` if the override or restore operation was successful.
*/
bool override_per_user_predefined_keys(HANDLE token) {
HKEY user_classes_root = nullptr;
HKEY user_classes_root = NULL;
if (token) {
auto err = RegOpenUserClassesRoot(token, 0, GENERIC_ALL, &user_classes_root);
if (err != ERROR_SUCCESS) {
@@ -573,14 +573,14 @@ namespace platf {
}
});
HKEY user_key = nullptr;
HKEY user_key = NULL;
if (token) {
impersonate_current_user(token, [&]() {
// RegOpenCurrentUser() doesn't take a token. It assumes we're impersonating the desired user.
auto err = RegOpenCurrentUser(GENERIC_ALL, &user_key);
if (err != ERROR_SUCCESS) {
BOOST_LOG(error) << "Failed to open user key for target user: "sv << err;
user_key = nullptr;
user_key = NULL;
}
});
if (!user_key) {
@@ -602,7 +602,7 @@ namespace platf {
err = RegOverridePredefKey(HKEY_CURRENT_USER, user_key);
if (err != ERROR_SUCCESS) {
BOOST_LOG(error) << "Failed to override HKEY_CURRENT_USER: "sv << err;
RegOverridePredefKey(HKEY_CLASSES_ROOT, nullptr);
RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
return false;
}
@@ -671,7 +671,7 @@ namespace platf {
* @details This converts URLs and non-executable file paths into a runnable command like ShellExecute().
* @param raw_cmd The raw command provided by the user.
* @param working_dir The working directory for the new process.
* @param token The user token currently being impersonated or `nullptr` if running as ourselves.
* @param token The user token currently being impersonated or `NULL` if running as ourselves.
* @param creation_flags The creation flags for CreateProcess(), which may be modified by this function.
* @return A command string suitable for use by CreateProcess().
*/
@@ -757,7 +757,7 @@ namespace platf {
}
// Reset per-user keys back to the original value
override_per_user_predefined_keys(nullptr);
override_per_user_predefined_keys(NULL);
}
if (res != S_OK) {
@@ -972,7 +972,7 @@ namespace platf {
ec = impersonate_current_user(user_token, [&]() {
std::wstring env_block = create_environment_block(cloned_env);
std::wstring wcmd = resolve_command_string(cmd, start_dir, user_token, creation_flags);
ret = CreateProcessAsUserW(user_token, nullptr, (LPWSTR) wcmd.c_str(), nullptr, nullptr, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), creation_flags, env_block.data(), start_dir.empty() ? nullptr : start_dir.c_str(), (LPSTARTUPINFOW) &startup_info, &process_info);
ret = CreateProcessAsUserW(user_token, NULL, (LPWSTR) wcmd.c_str(), NULL, NULL, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), creation_flags, env_block.data(), start_dir.empty() ? NULL : start_dir.c_str(), (LPSTARTUPINFOW) &startup_info, &process_info);
});
}
// Otherwise, launch the process using CreateProcessW()
@@ -995,8 +995,8 @@ namespace platf {
}
std::wstring env_block = create_environment_block(cloned_env);
std::wstring wcmd = resolve_command_string(cmd, start_dir, nullptr, creation_flags);
ret = CreateProcessW(nullptr, (LPWSTR) wcmd.c_str(), nullptr, nullptr, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), creation_flags, env_block.data(), start_dir.empty() ? nullptr : start_dir.c_str(), (LPSTARTUPINFOW) &startup_info, &process_info);
std::wstring wcmd = resolve_command_string(cmd, start_dir, NULL, creation_flags);
ret = CreateProcessW(NULL, (LPWSTR) wcmd.c_str(), NULL, NULL, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), creation_flags, env_block.data(), start_dir.empty() ? NULL : start_dir.c_str(), (LPSTARTUPINFOW) &startup_info, &process_info);
}
// Use the results of the launch to create a bp::child object
@@ -1052,7 +1052,7 @@ namespace platf {
static std::once_flag load_wlanapi_once_flag;
std::call_once(load_wlanapi_once_flag, []() {
// wlanapi.dll is not installed by default on Windows Server, so we load it dynamically
HMODULE wlanapi = LoadLibraryExA("wlanapi.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
HMODULE wlanapi = LoadLibraryExA("wlanapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!wlanapi) {
BOOST_LOG(debug) << "wlanapi.dll is not available on this OS"sv;
return;
@@ -1129,7 +1129,7 @@ namespace platf {
fn_WlanFreeMemory(wlan_interface_list);
} else {
fn_WlanCloseHandle(wlan_handle, nullptr);
wlan_handle = nullptr;
wlan_handle = NULL;
}
}
}
@@ -1200,7 +1200,7 @@ namespace platf {
startup_info.StartupInfo.cb = sizeof(startup_info);
WCHAR executable[MAX_PATH];
if (GetModuleFileNameW(nullptr, executable, ARRAYSIZE(executable)) == 0) {
if (GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable)) == 0) {
auto winerr = GetLastError();
BOOST_LOG(fatal) << "Failed to get Sunshine path: "sv << winerr;
return;
@@ -1220,7 +1220,7 @@ namespace platf {
void restart() {
// If we're running standalone, we have to respawn ourselves via CreateProcess().
// If we're running from the service, we should just exit and let it respawn us.
if (GetConsoleWindow() != nullptr) {
if (GetConsoleWindow() != NULL) {
// Avoid racing with the new process by waiting until we're exiting to start it.
atexit(restart_on_exit);
}
@@ -1538,7 +1538,7 @@ namespace platf {
}
virtual ~qos_t() {
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) nullptr, flow_id, 0)) {
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) NULL, flow_id, 0)) {
auto winerr = GetLastError();
BOOST_LOG(warning) << "QOSRemoveSocketFromFlow() failed: "sv << winerr;
}
@@ -1570,7 +1570,7 @@ namespace platf {
static std::once_flag load_qwave_once_flag;
std::call_once(load_qwave_once_flag, []() {
// qWAVE is not installed by default on Windows Server, so we load it dynamically
HMODULE qwave = LoadLibraryExA("qwave.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
HMODULE qwave = LoadLibraryExA("qwave.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!qwave) {
BOOST_LOG(debug) << "qwave.dll is not available on this OS"sv;
return;
@@ -1788,11 +1788,11 @@ namespace platf {
}
operator bool() override {
return timer != nullptr;
return timer != NULL;
}
private:
HANDLE timer = nullptr;
HANDLE timer = NULL;
};
std::unique_ptr<high_precision_timer> create_high_precision_timer() {

View File

@@ -9,7 +9,7 @@
#include <string_view>
// platform includes
#include <Windows.h>
#include <windows.h>
#include <winnt.h>
namespace platf {

View File

@@ -60,7 +60,7 @@ namespace nvprefs {
void driver_settings_t::destroy() {
if (session_handle) {
NvAPI_DRS_DestroySession(session_handle);
session_handle = nullptr;
session_handle = 0;
}
NvAPI_Unload();
}
@@ -105,7 +105,7 @@ namespace nvprefs {
if (swapchain_data) {
NvAPI_Status status;
NvDRSProfileHandle profile_handle = nullptr;
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_GetBaseProfile(session_handle, &profile_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
@@ -168,7 +168,7 @@ namespace nvprefs {
return true;
}
NvDRSProfileHandle profile_handle = nullptr;
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_GetBaseProfile(session_handle, &profile_handle);
if (status != NVAPI_OK) {
nvapi_error_message(status);
@@ -224,7 +224,7 @@ namespace nvprefs {
NvAPI_UnicodeString profile_name = {};
fill_nvapi_string(profile_name, sunshine_application_profile_name);
NvDRSProfileHandle profile_handle = nullptr;
NvDRSProfileHandle profile_handle = 0;
status = NvAPI_DRS_FindProfileByName(session_handle, profile_name, &profile_handle);
if (status != NVAPI_OK) {

View File

@@ -36,7 +36,7 @@ namespace nvprefs {
bool check_and_modify_application_profile(bool &modified);
private:
NvDRSSessionHandle session_handle = nullptr;
NvDRSSessionHandle session_handle = 0;
};
} // namespace nvprefs

View File

@@ -15,7 +15,7 @@
namespace {
std::map<const char *, void *> interfaces;
HMODULE dll = nullptr;
HMODULE dll = NULL;
template<typename Func, typename... Args>
NvAPI_Status call_interface(const char *name, Args... args) {
@@ -47,7 +47,7 @@ NvAPI_Initialize() {
auto dll_name = "nvapi.dll";
#endif
if ((dll = LoadLibraryEx(dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
if ((dll = LoadLibraryEx(dll_name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
if (auto query_interface = (decltype(nvapi_QueryInterface) *) GetProcAddress(dll, "nvapi_QueryInterface")) {
for (const auto &item : nvapi_interface_table) {
interfaces[item.func] = query_interface(item.id);
@@ -64,7 +64,7 @@ NVAPI_INTERFACE NvAPI_Unload() {
if (dll) {
interfaces.clear();
FreeLibrary(dll);
dll = nullptr;
dll = NULL;
}
return NVAPI_OK;
}

View File

@@ -7,8 +7,8 @@
// platform includes
// disable clang-format header reordering
// clang-format off
#include <Windows.h>
#include <AclAPI.h>
#include <windows.h>
#include <aclapi.h>
// clang-format on
// local includes
@@ -21,7 +21,7 @@ namespace nvprefs {
explicit operator bool() const {
auto handle = get();
return handle != nullptr && handle != INVALID_HANDLE_VALUE;
return handle != NULL && handle != INVALID_HANDLE_VALUE;
}
};

View File

@@ -51,7 +51,7 @@ namespace nvprefs {
std::optional<undo_file_t> undo_file_t::open_existing_file(std::filesystem::path file_path, bool &access_denied) {
undo_file_t file;
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_READ | DELETE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_READ | DELETE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
if (file.file_handle) {
access_denied = false;
return file;
@@ -64,7 +64,7 @@ namespace nvprefs {
std::optional<undo_file_t> undo_file_t::create_new_file(std::filesystem::path file_path) {
undo_file_t file;
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_WRITE | STANDARD_RIGHTS_ALL, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr));
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_WRITE | STANDARD_RIGHTS_ALL, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL));
if (file.file_handle) {
// give GENERIC_READ, GENERIC_WRITE and DELETE permissions to Users group

View File

@@ -3,12 +3,12 @@
* @brief Definitions for Windows mDNS service registration.
*/
// platform includes
// WinSock2.h must be included before Windows.h
// winsock2.h must be included before windows.h
// clang-format off
#include <WinSock2.h>
#include <Windows.h>
#include <winsock2.h>
#include <windows.h>
// clang-format on
#include <WinDNS.h>
#include <windns.h>
#include <winerror.h>
// local includes

View File

@@ -158,7 +158,7 @@ namespace proc {
_env["SUNSHINE_CLIENT_GCMAP"] = std::to_string(launch_session->gcmap);
_env["SUNSHINE_CLIENT_HOST_AUDIO"] = launch_session->host_audio ? "true" : "false";
_env["SUNSHINE_CLIENT_ENABLE_SOPS"] = launch_session->enable_sops ? "true" : "false";
int channelCount = launch_session->surround_info & 65535;
int channelCount = launch_session->surround_info & (65535);
switch (channelCount) {
case 2:
_env["SUNSHINE_CLIENT_AUDIO_CONFIGURATION"] = "2.0";

View File

@@ -12,7 +12,6 @@ extern "C" {
// standard includes
#include <array>
#include <cctype>
#include <format>
#include <set>
#include <unordered_map>
#include <utility>
@@ -433,6 +432,11 @@ namespace rtsp_stream {
return 0;
}
template<class T, class X>
void iterate(std::chrono::duration<T, X> timeout) {
io_context.run_one_for(timeout);
}
void handle_msg(tcp::socket &sock, launch_session_t &session, msg_t &&req) {
auto func = _map_cmd_cb.find(req->message.request.command);
if (func != std::end(_map_cmd_cb)) {
@@ -490,24 +494,15 @@ namespace rtsp_stream {
* @param launch_session Streaming session information.
*/
void session_raise(std::shared_ptr<launch_session_t> launch_session) {
auto now = std::chrono::steady_clock::now();
// If a launch event is still pending, don't overwrite it.
if (launch_event.view(0s)) {
if (raised_timeout > now && launch_event.peek()) {
return;
}
raised_timeout = now + config::stream.ping_timeout;
// Raise the new launch session to prepare for the RTSP handshake
launch_event.raise(std::move(launch_session));
// Arm the timer to expire this launch session if the client times out
raised_timer.expires_after(config::stream.ping_timeout);
raised_timer.async_wait([this](const boost::system::error_code &ec) {
if (!ec) {
auto discarded = launch_event.pop(0s);
if (discarded) {
BOOST_LOG(debug) << "Event timeout: "sv << discarded->unique_id;
}
}
});
}
/**
@@ -522,7 +517,6 @@ namespace rtsp_stream {
if (launch_session->id != launch_session_id) {
BOOST_LOG(error) << "Attempted to clear unexpected session: "sv << launch_session_id << " vs "sv << launch_session->id;
} else {
raised_timer.cancel();
launch_event.pop();
}
}
@@ -547,6 +541,14 @@ namespace rtsp_stream {
* @examples_end
*/
void clear(bool all = true) {
// if a launch event timed out --> Remove it.
if (raised_timeout < std::chrono::steady_clock::now()) {
auto discarded = launch_event.pop(0s);
if (discarded) {
BOOST_LOG(debug) << "Event timeout: "sv << discarded->unique_id;
}
}
auto lg = _session_slots.lock();
for (auto i = _session_slots->begin(); i != _session_slots->end();) {
@@ -581,36 +583,15 @@ namespace rtsp_stream {
BOOST_LOG(info) << "New streaming session started [active sessions: "sv << _session_slots->size() << ']';
}
/**
* @brief Runs an iteration of the RTSP server loop
*/
void iterate() {
// If we have a session, we will return to the server loop every
// 500ms to allow session cleanup to happen.
if (session_count() > 0) {
io_context.run_one_for(500ms);
} else {
io_context.run_one();
}
}
/**
* @brief Stop the RTSP server.
*/
void stop() {
acceptor.close();
io_context.stop();
clear();
}
private:
std::unordered_map<std::string_view, cmd_func_t> _map_cmd_cb;
sync_util::sync_t<std::set<std::shared_ptr<stream::session_t>>> _session_slots;
std::chrono::steady_clock::time_point raised_timeout;
boost::asio::io_context io_context;
tcp::acceptor acceptor {io_context};
boost::asio::steady_timer raised_timer {io_context};
std::shared_ptr<socket_t> next_socket;
};
@@ -865,7 +846,7 @@ namespace rtsp_stream {
session_option.next = &port_option;
// Moonlight merely requires 'server_port=<port>'
auto port_value = std::format("server_port={}", static_cast<int>(port));
auto port_value = "server_port=" + std::to_string(port);
port_option.option = const_cast<char *>("Transport");
port_option.content = port_value.data();
@@ -1107,8 +1088,9 @@ namespace rtsp_stream {
respond(sock, session, &option, 200, "OK", req->sequenceNumber, {});
}
void start() {
void rtpThread() {
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
server.map("OPTIONS"sv, &cmd_option);
server.map("DESCRIBE"sv, &cmd_describe);
@@ -1124,29 +1106,18 @@ namespace rtsp_stream {
return;
}
std::thread rtsp_thread {[&shutdown_event] {
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
while (!shutdown_event->peek()) {
server.iterate(std::min(500ms, config::stream.ping_timeout));
while (!shutdown_event->peek()) {
server.iterate();
if (broadcast_shutdown_event->peek()) {
server.clear();
} else {
// cleanup all stopped sessions
server.clear(false);
}
if (broadcast_shutdown_event->peek()) {
server.clear();
} else {
// cleanup all stopped sessions
server.clear(false);
}
}
server.clear();
}};
// Wait for shutdown
shutdown_event->view();
// Stop the server and join the server thread
server.stop();
rtsp_thread.join();
server.clear();
}
void print_msg(PRTSP_MESSAGE msg) {

View File

@@ -59,8 +59,6 @@ namespace rtsp_stream {
*/
void terminate_sessions();
/**
* @brief Runs the RTSP server loop.
*/
void start();
void rtpThread();
} // namespace rtsp_stream

View File

@@ -84,7 +84,7 @@ namespace system_tray {
#ifdef _WIN32
// If we're running in a service, return a special status to
// tell it to terminate too, otherwise it will just respawn us.
if (GetConsoleWindow() == nullptr) {
if (GetConsoleWindow() == NULL) {
lifetime::exit_sunshine(ERROR_SHUTDOWN_IN_PROGRESS, true);
return;
}
@@ -230,10 +230,10 @@ namespace system_tray {
return;
}
tray.notification_title = nullptr;
tray.notification_text = nullptr;
tray.notification_cb = nullptr;
tray.notification_icon = nullptr;
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
tray.notification_icon = NULL;
tray.icon = TRAY_ICON_PLAYING;
tray_update(&tray);
tray.icon = TRAY_ICON_PLAYING;
@@ -251,10 +251,10 @@ namespace system_tray {
return;
}
tray.notification_title = nullptr;
tray.notification_text = nullptr;
tray.notification_cb = nullptr;
tray.notification_icon = nullptr;
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
tray.notification_icon = NULL;
tray.icon = TRAY_ICON_PAUSING;
tray_update(&tray);
char msg[256];
@@ -272,10 +272,10 @@ namespace system_tray {
return;
}
tray.notification_title = nullptr;
tray.notification_text = nullptr;
tray.notification_cb = nullptr;
tray.notification_icon = nullptr;
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
tray.notification_icon = NULL;
tray.icon = TRAY_ICON;
tray_update(&tray);
char msg[256];
@@ -293,10 +293,10 @@ namespace system_tray {
return;
}
tray.notification_title = nullptr;
tray.notification_text = nullptr;
tray.notification_cb = nullptr;
tray.notification_icon = nullptr;
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
tray.notification_icon = NULL;
tray.icon = TRAY_ICON;
tray_update(&tray);
tray.icon = TRAY_ICON;
@@ -305,7 +305,7 @@ namespace system_tray {
tray.notification_icon = TRAY_ICON_LOCKED;
tray.tooltip = PROJECT_NAME;
tray.notification_cb = []() {
launch_ui("/pin");
launch_ui_with_path("/pin");
};
tray_update(&tray);
}

View File

@@ -765,18 +765,6 @@ namespace video {
{"usage"s, &config::video.amd.amd_usage_hevc},
{"vbaq"s, &config::video.amd.amd_vbaq},
{"enforce_hrd"s, &config::video.amd.amd_enforce_hrd},
{"level"s, [](const config_t &cfg) {
auto size = cfg.width * cfg.height;
// For 4K and below, try to use level 5.1 or 5.2 if possible
if (size <= 8912896) {
if (size * cfg.framerate <= 534773760) {
return "5.1"s;
} else if (size * cfg.framerate <= 1069547520) {
return "5.2"s;
}
}
return "auto"s;
}},
},
{}, // SDR-specific options
{}, // HDR-specific options
@@ -1651,7 +1639,7 @@ namespace video {
ctx->thread_count = ctx->slices;
AVDictionary *options {nullptr};
auto handle_option = [&options, &config](const encoder_t::option_t &option) {
auto handle_option = [&options](const encoder_t::option_t &option) {
std::visit(
util::overloaded {
[&](int v) {
@@ -1665,7 +1653,7 @@ namespace video {
av_dict_set_int(&options, option.name.c_str(), **v, 0);
}
},
[&](const std::function<int()> &v) {
[&](std::function<int()> v) {
av_dict_set_int(&options, option.name.c_str(), v(), 0);
},
[&](const std::string &v) {
@@ -1675,9 +1663,6 @@ namespace video {
if (!v->empty()) {
av_dict_set(&options, option.name.c_str(), v->c_str(), 0);
}
},
[&](const std::function<const std::string(const config_t &cfg)> &v) {
av_dict_set(&options, option.name.c_str(), v(config).c_str(), 0);
}
},
option.value
@@ -1890,10 +1875,9 @@ namespace video {
}
});
// set max frame time based on client-requested target framerate.
double minimum_fps_target = (config::video.minimum_fps_target > 0.0) ? config::video.minimum_fps_target : config.framerate;
std::chrono::duration<double, std::milli> max_frametime {1000.0 / minimum_fps_target};
BOOST_LOG(info) << "Minimum FPS target set to ~"sv << (minimum_fps_target / 2) << "fps ("sv << max_frametime.count() * 2 << "ms)"sv;
// set minimum frame time based on client-requested target framerate
std::chrono::duration<double, std::milli> minimum_frame_time {1000.0 / config.framerate};
BOOST_LOG(info) << "Minimum frame time set to "sv << minimum_frame_time.count() << "ms, based on client-requested target framerate "sv << config.framerate << "."sv;
auto shutdown_event = mail->event<bool>(mail::shutdown);
auto packets = mail::man->queue<packet_t>(mail::video_packets);
@@ -1944,7 +1928,7 @@ namespace video {
// Encode at a minimum FPS to avoid image quality issues with static content
if (!requested_idr_frame || images->peek()) {
if (auto img = images->pop(max_frametime)) {
if (auto img = images->pop(minimum_frame_time)) {
frame_timestamp = img->frame_timestamp;
if (session->convert(*img)) {
BOOST_LOG(error) << "Could not convert image"sv;

View File

@@ -150,7 +150,7 @@ namespace video {
option_t(const option_t &) = default;
std::string name;
std::variant<int, int *, std::optional<int> *, std::function<int()>, std::string, std::string *, std::function<const std::string(const config_t &)>> value;
std::variant<int, int *, std::optional<int> *, std::function<int()>, std::string, std::string *> value;
option_t(std::string &&name, decltype(value) &&value):
name {std::move(name)},

View File

@@ -179,7 +179,6 @@
"dd_mode_remapping": {"mixed": [], "resolution_only": [], "refresh_rate_only": []},
"dd_wa_hdr_toggle_delay": 0,
"max_bitrate": 0,
"minimum_fps_target": 0
},
},
{

View File

@@ -1,7 +1,6 @@
<script setup>
import { ref } from 'vue'
import PlatformLayout from '../../../PlatformLayout.vue'
import Checkbox from "../../../Checkbox.vue";
const props = defineProps({
platform: String,

View File

@@ -17,13 +17,6 @@ const config = ref(props.config)
<input type="number" class="form-control" id="max_bitrate" placeholder="0" v-model="config.max_bitrate" />
<div class="form-text">{{ $t("config.max_bitrate_desc") }}</div>
</div>
<!--minimum_fps_target-->
<div class="mb-3">
<label for="minimum_fps_target" class="form-label">{{ $t("config.minimum_fps_target") }}</label>
<input type="number" min="0" max="1000" class="form-control" id="minimum_fps_target" placeholder="0" v-model="config.minimum_fps_target" />
<div class="form-text">{{ $t("config.minimum_fps_target_desc") }}</div>
</div>
</template>
<style scoped>

View File

@@ -137,129 +137,129 @@
"av1_mode_3": "Sunshine bude inzerovat podporu hlavních 8bitových a 10bitových profilů AV1 (HDR)",
"av1_mode_desc": "Umožňuje klientovi požádat o AV1 hlavní 8-bitové nebo 10-bitové video streamy. AV1 je intenzivnější na CPU kódování, takže díky tomu může dojít ke snížení výkonu při používání kódování softwaru.",
"back_button_timeout": "Časový limit emulace tlačítka Domů/Návod",
"back_button_timeout_desc": "Pokud je tlačítko Zpět/Vybrat podrženo po zadaný počet milisekund, je emulováno stisknutí tlačítka Domů/Průvodce. Pokud je nastavena hodnota < 0 (výchozí), podržením tlačítka Zpět/Vybrat se tlačítko Domů/Průvodce neemuluje.",
"back_button_timeout_desc": "Pokud je tlačítko Zpět/Výběr podrženo pro zadaný počet milisekund, je emulováno stisknutí tlačítka Domů/Průvodce. Je-li nastaveno na hodnotu < 0 (výchozí), podržením tlačítka Zpět/Výběr nebude tlačítko Domů/Průvodce emulováno.",
"capture": "Vynutit specifickou metodu snímání",
"capture_desc": "V automatickém režimu Sunshine použije první, který funguje. NvFBC vyžaduje opravené ovladače nvidia.",
"cert": "Certifikát",
"cert_desc": "Certifikát použitý pro párování webového uživatelského rozhraní a klienta Moonlight. Kvůli nejlepší kompatibilitě by měl mít veřejný klíč RSA-2048.",
"capture_desc": "V automatickém režimu bude Sunshine používat ten první, který funguje. NvFBC vyžaduje upravené nvidia ovladače.",
"cert": "Osvědčení",
"cert_desc": "Certifikát používaný pro párování webových UI a Moonlight klientů. Pro nejlepší kompatibilitu by měl mít veřejný klíč RSA-2048.",
"channels": "Maximální počet připojených klientů",
"channels_desc_1": "Sunshine může umožnit sdílení jedné relace streamování s více klienty současně.",
"channels_desc_1": "Sluneční svár může umožnit sdílení jediné streamovací relace s více klienty současně.",
"channels_desc_2": "Některé hardwarové enkodéry mohou mít omezení, která snižují výkon s více streamy.",
"coder_cabac": "cabac -- kontextové binární aritmetické kódování vyšší kvalita",
"coder_cavlc": "cavlc -- kontextové adaptivní kódování variabilní délky - rychlejší dekódování",
"configuration": "Konfigurace",
"controller": "Povolení vstupu z gamepadu",
"controller_desc": "Umožňuje hostům ovládat hostitelský systém pomocí gamepadu/ovladače",
"controller": "Enable Gamepad Input",
"controller_desc": "Umožňuje hostům ovládat hostitelský systém pomocí gamepad / controller",
"credentials_file": "Soubor pověření",
"credentials_file_desc": "Uživatelské jméno/heslo ukládejte odděleně od souboru stavu Sunshine.",
"credentials_file_desc": "Uložit uživatelské jméno/heslo odděleně od souboru se stavem Sunshine.",
"dd_config_ensure_active": "Automaticky aktivovat displej",
"dd_config_ensure_only_display": "Deaktivovat další displeje a aktivovat pouze zadaný displej",
"dd_config_ensure_primary": "Automaticky aktivovat displej a učinit jej primárním displejem",
"dd_config_label": "Konfigurace zařízení",
"dd_config_revert_delay": "Zpoždění vrácení konfigurace",
"dd_config_revert_delay_desc": "Dodatečná prodleva v milisekundách, která má být vyčkána před vrácením konfigurace, pokud byla aplikace zavřena nebo poslední relace ukončena. Hlavním účelem je zajistit plynulejší přechod při rychlém přepínání mezi aplikacemi.",
"dd_config_revert_on_disconnect": "Vrácení konfigurace při odpojení",
"dd_config_revert_on_disconnect_desc": "Vrácení konfigurace při odpojení všech klientů místo ukončení aplikace nebo poslední relace.",
"dd_config_revert_delay": "Zpoždění nastavení zpětného chodu",
"dd_config_revert_delay_desc": "Další zpoždění v milisekundách če na obnovení konfigurace při zavření aplikace nebo ukončení poslední relace. Hlavním účelem je zajistit hladký přechod při rychlém přepínání mezi aplikacemi.",
"dd_config_revert_on_disconnect": "Konfigurace se vrátí po odpojení",
"dd_config_revert_on_disconnect_desc": "Vrátit konfiguraci po odpojení všech klientů namísto zavření aplikace nebo posledního ukončení relace.",
"dd_config_verify_only": "Ověřte, zda je displej povolen",
"dd_hdr_option": "HDR",
"dd_hdr_option_auto": "Zapnout/vypnout HDR režim podle požadavku klienta (výchozí)",
"dd_hdr_option_disabled": "Neměnit nastavení HDR",
"dd_mode_remapping": "Přemapování režimu zobrazení",
"dd_mode_remapping": "Režim zobrazení přemapování",
"dd_mode_remapping_add": "Přidat položku pro nové mapování",
"dd_mode_remapping_desc_1": "Určete položky pro nové mapování pro změnu požadovaného rozlišení a/nebo obnovení frekvence na jiné hodnoty.",
"dd_mode_remapping_desc_2": "Seznam se iteruje shora dolů a použije se první shoda.",
"dd_mode_remapping_desc_3": "Pole \"Požadováno\" mohou být ponechána prázdná, aby odpovídala libovolné požadované hodnotě.",
"dd_mode_remapping_desc_4_final_values_mixed": "Musí být zadáno alespoň jedno pole \"Final\". Nezadané rozlišení nebo obnovovací frekvence se nezmění.",
"dd_mode_remapping_desc_4_final_values_mixed": "Alespoň jedno pole \"Final\" musí být zadáno. Nespecifikované rozlišení nebo obnovovací frekvence se nezmění.",
"dd_mode_remapping_desc_4_final_values_non_mixed": "Pole \"Final\" musí být zadáno a nesmí být prázdné.",
"dd_mode_remapping_desc_5_sops_mixed_only": "V klientovi Moonlight musí být povolena možnost \"Optimalizovat nastavení hry\", jinak budou položky se zadanými poli rozlišení přeskočeny.",
"dd_mode_remapping_desc_5_sops_resolution_only": "V klientovi Moonlight musí být povolena možnost \"Optimalizovat nastavení hry\", jinak se mapování přeskočí.",
"dd_mode_remapping_desc_5_sops_mixed_only": "Možnost \"Optimalizovat nastavení hry\" musí být povolena v klientovi Měsíční světlo, jinak budou přeskočeny záznamy s libovolnými vybranými rozlišeními polí.",
"dd_mode_remapping_desc_5_sops_resolution_only": "Možnost \"Optimalizovat nastavení hry\" musí být povolena v klientovi Měsíční světlo, jinak je mapování přeskočeno.",
"dd_mode_remapping_final_refresh_rate": "Konečná obnovovací frekvence",
"dd_mode_remapping_final_resolution": "Konečné rozlišení",
"dd_mode_remapping_requested_fps": "Požadované FPS",
"dd_mode_remapping_final_resolution": "Konečné řešení",
"dd_mode_remapping_requested_fps": "Požadovaná FPS",
"dd_mode_remapping_requested_resolution": "Požadované rozlišení",
"dd_options_header": "Rozšířené možnosti displeje",
"dd_refresh_rate_option": "Obnovovací frekvence",
"dd_refresh_rate_option_auto": "Použít hodnotu FPS zadanou klientem (výchozí)",
"dd_refresh_rate_option_auto": "Použít FPS hodnotu poskytnutou klientem (výchozí)",
"dd_refresh_rate_option_disabled": "Neměnit obnovovací frekvenci",
"dd_refresh_rate_option_manual": "Použít ručně zadanou obnovovací frekvenci",
"dd_refresh_rate_option_manual_desc": "Zadejte obnovovací frekvenci, která se má použít",
"dd_refresh_rate_option_manual_desc": "Zadejte obnovovací frekvenci pro použití",
"dd_resolution_option": "Rozlišení",
"dd_resolution_option_auto": "Použít rozlišení poskytované klientem (výchozí)",
"dd_resolution_option_disabled": "Neměnit rozlišení",
"dd_resolution_option_manual": "Použít ručně zadané rozlišení",
"dd_resolution_option_manual_desc": "Zadejte rozlišení, které má být použito",
"dd_resolution_option_ogs_desc": "Aby tato funkce fungovala, musí být v klientovi Moonlight povolena možnost \"Optimalizovat nastavení hry\".",
"dd_wa_hdr_toggle_delay_desc_1": "Při použití virtuálního zobrazovacího zařízení (VDD) pro streamování může dojít k nesprávnému zobrazení barev HDR. Sunshine se může pokusit tento problém zmírnit vypnutím a opětovným zapnutím HDR.",
"dd_wa_hdr_toggle_delay_desc_2": "Pokud je hodnota nastavena na 0, je obcházení zakázáno (výchozí nastavení). Pokud je hodnota v rozmezí 0 až 3000 milisekund, Sunshine vypne HDR, počká zadanou dobu a poté HDR opět zapne. Doporučená doba zpoždění je ve většině případů přibližně 500 milisekund.",
"dd_wa_hdr_toggle_delay_desc_3": "NEPOUŽÍVEJTE toto řešení, pokud skutečně nemáte problémy s HDR, protože přímo ovlivňuje čas spuštění streamu!",
"dd_wa_hdr_toggle_delay": "Řešení pro HDR s vysokým kontrastem",
"ds4_back_as_touchpad_click": "Namapovat Zpět/Vybrat na klepnutí touchpadu",
"ds4_back_as_touchpad_click_desc": "Při vynucení emulace DS4 namapujte funkci Zpět/Vybrat na klepnutí touchpadu",
"dd_resolution_option_ogs_desc": "Možnost \"Optimalizovat nastavení hry\" musí být povolena na klientovi Moonlight aby to fungovalo.",
"dd_wa_hdr_toggle_delay_desc_1": "Při použití virtuálního displeje (VDD) pro vysílání může nesprávně zobrazit barvu HDR. Sluneční svár se může pokusit tento problém zmírnit tím, že vypne HDR a poté znovu vypne.",
"dd_wa_hdr_toggle_delay_desc_2": "Pokud je hodnota nastavena na 0, je práce zakázána (výchozí). Pokud je hodnota mezi 0 a 3000 milisekundami, sunshine vypne HDR, počkejte na stanovený čas a pak znovu zapněte HDR. Doporučená doba zpoždění je ve většině případů přibližně 500 milisekund.",
"dd_wa_hdr_toggle_delay_desc_3": "NEPOUŽÍVEJTE toto fungování, pokud nemáte problémy s HDR protože přímo ovlivňuje počáteční čas!",
"dd_wa_hdr_toggle_delay": "Práce na vysokém kontrastu pro HDR",
"ds4_back_as_touchpad_click": "Mapa zpátky/Vyberte pro klepnutí na Touchpad",
"ds4_back_as_touchpad_click_desc": "Při vynucení emulace DS4 mapa zpět/Vyberte na Touchpad kliknutí",
"encoder": "Vynutit specifický enkodér",
"encoder_desc": "Vynutit konkrétní kodér, jinak Sunshine vybere nejlepší dostupnou možnost. Poznámka: Pokud v systému Windows zadáte hardwarový kodér, musí odpovídat grafickému procesoru, ke kterému je displej připojen.",
"encoder_software": "Software",
"encoder_desc": "Vynutit konkrétní enkodér, jinak Sunshine vybere nejlepší dostupnou možnost. Poznámka: Pokud zadáte hardwarový enkodér v systému Windows, musí odpovídat GPU, kde je displej připojen.",
"encoder_software": "Programové vybavení",
"external_ip": "Externí IP",
"external_ip_desc": "Pokud není zadána žádná externí IP adresa, Sunshine automaticky zjistí externí IP adresu",
"external_ip_desc": "Pokud není zadána žádná externí IP adresa, Sluneční server automaticky rozpozná externí IP adresu",
"fec_percentage": "Procento FEC",
"fec_percentage_desc": "Procento paketů pro opravu chyb v každém datovém paketu v každém videosnímku. Vyšší hodnoty mohou korigovat větší ztráty síťových paketů, ale za cenu zvýšení využití šířky pásma.",
"ffmpeg_auto": "auto -- nechat ffmpeg rozhodnout (výchozí)",
"fec_percentage_desc": "Procento chyb při opravě paketů na datových paketech v každém video snímku. Vyšší hodnoty mohou opravit větší ztrátu síťových paketů, ale za cenu zvýšení využití šířky pásma.",
"ffmpeg_auto": "auto -- nechat rozhodnutí ffmpeg (výchozí)",
"file_apps": "Soubor aplikací",
"file_apps_desc": "Soubor, ve kterém jsou uloženy aktuální aplikace Sunshine.",
"file_state": "Stavový soubor",
"file_state_desc": "Soubor, ve kterém je uložen aktuální stav Sunshine",
"gamepad": "Typ emulovaného gamepadu",
"file_apps_desc": "Soubor, kde jsou uloženy aktuální aplikace Sunshine.",
"file_state": "Státní soubor",
"file_state_desc": "Soubor, ve kterém je uložen aktuální stav sunshine",
"gamepad": "Emulovaný typ hry",
"gamepad_auto": "Možnosti automatického výběru",
"gamepad_desc": "Výběr typu gamepadu pro emulaci v hostitelském počítači",
"gamepad_desc": "Vyberte typ gamepadu, který chcete emulovat na hostiteli",
"gamepad_ds4": "DS4 (PS4)",
"gamepad_ds4_manual": "Možnosti výběru DS4",
"gamepad_ds5": "DS5 (PS5)",
"gamepad_switch": "Nintendo Pro (Switch)",
"gamepad_manual": "Možnosti manuálního ovládání DS4",
"gamepad_manual": "Možnosti manuálního DS4",
"gamepad_x360": "X360 (Xbox 360)",
"gamepad_xone": "XOne (Xbox One)",
"gamepad_xone": "Xone (Xbox Jedna)",
"global_prep_cmd": "Příprava příkazů",
"global_prep_cmd_desc": "Konfigurace seznamu příkazů, které se mají spustit před nebo po spuštění libovolné aplikace. Pokud některý ze zadaných přípravných příkazů selže, proces spuštění aplikace se přeruší.",
"global_prep_cmd_desc": "Konfigurace seznamu příkazů, které mají být provedeny před spuštěním jakékoli aplikace nebo po ní. Pokud některý z určených příkazů neuspěje, proces spuštění aplikace bude přerušen.",
"hevc_mode": "Podpora HEVC",
"hevc_mode_0": "Sunshine bude propagovat podporu pro HEVC na základě možností enkodéru (doporučeno)",
"hevc_mode_1": "Sunshine nebude inzerovat podporu HEVC",
"hevc_mode_2": "Sunshine bude inzerovat podporu hlavního profilu HEVC",
"hevc_mode_3": "Sunshine bude inzerovat podporu profilů HEVC Main a Main10 (HDR)",
"hevc_mode_desc": "Umožňuje klientovi vyžádat videostreamy HEVC Main nebo HEVC Main10. Kódování HEVC je náročnější na procesor, takže zapnutí této funkce může snížit výkon při použití softwarového kódování.",
"hevc_mode_1": "Sluneční síť nebude propagovat podporu HEVC",
"hevc_mode_2": "Sluneční svaz bude propagovat podporu hlavního profilu HEVC",
"hevc_mode_3": "Sluneční svaz bude propagovat podporu profilů HEVC Main a Main10 (HDR)",
"hevc_mode_desc": "Umožňuje klientovi vyžádat si HEVC Main nebo HEVC Main10 video streamy. HEVC je intenzivnější na CPU kódování, takže povolení může snížit výkon při používání kódování softwaru.",
"high_resolution_scrolling": "Podpora rolování s vysokým rozlišením",
"high_resolution_scrolling_desc": "Je-li tato funkce povolena, bude Sunshine předávat události posouvání ve vysokém rozlišení od klientů Moonlight. To může být užitečné zakázat u starších aplikací, které se při událostech posouvání ve vysokém rozlišení posouvají příliš rychle.",
"install_steam_audio_drivers": "Instalace ovladačů zvuku služby Steam",
"install_steam_audio_drivers_desc": "Pokud je nainstalována služba Steam, automaticky se nainstaluje ovladač Steam Streaming Speakers pro podporu prostorového zvuku 5.1/7.1 a ztlumení zvuku hostitele.",
"key_repeat_delay": "Zpoždění opakování kláves",
"key_repeat_delay_desc": "Ovládání rychlosti opakování kláves. Počáteční prodleva v milisekundách před opakováním kláves.",
"key_repeat_frequency": "Frekvence opakování kláves",
"key_repeat_frequency_desc": "Jak často se klávesy opakují každou sekundu. Tato nastavitelná možnost podporuje desetinná čísla.",
"key_rightalt_to_key_win": "Mapování pravé klávesy Alt na klávesu Windows",
"key_rightalt_to_key_win_desc": "Je možné, že klávesa Windows nelze odeslat přímo z aplikace Moonlight. V takových případech může být užitečné přimět Sunshine, aby si myslel, že pravý Alt je klávesa Windows",
"keyboard": "Povolit vstupu z klávesnice",
"high_resolution_scrolling_desc": "Pokud je povoleno, sunshine projde událostmi posunu s vysokým rozlišením od klientů Moonight. To může být užitečné pro vypnutí starších aplikací, které se posouvají příliš rychle při posunu s vysokým rozlišením.",
"install_steam_audio_drivers": "Nainstalujte Steam Audio Drivers",
"install_steam_audio_drivers_desc": "Pokud je Steam nainstalován, tak se automaticky nainstaluje ovladač Steam Streaming Speakers pro podporu 5.1/7.1 prostorového zvuku a ztlumení zvuku.",
"key_repeat_delay": "Zpoždění opakování klíče",
"key_repeat_delay_desc": "Ovládejte, jak rychle se budou klíče opakovat. Počáteční zpoždění v milisekundách před opakováním klíčů.",
"key_repeat_frequency": "Frekvence opakování klíče",
"key_repeat_frequency_desc": "Jak často se klíče opakují každou vteřinu. Tato konfigurovatelná volba podporuje desetinná místa.",
"key_rightalt_to_key_win": "Mapovat pravý Alt klíč k klíči Windows",
"key_rightalt_to_key_win_desc": "Může být možné, že z Moonlight nemůžete přímo odeslat klíč pro Windows. V těchto případech může být užitečné udělat sunshine si myslet, že klíč pravý Alt je klíč pro Windows",
"keyboard": "Povolit vstup klávesnice",
"keyboard_desc": "Umožňuje hostům ovládat hostitelský systém pomocí klávesnice",
"lan_encryption_mode": "Režim šifrování LAN",
"lan_encryption_mode_1": "Povoleno pro podporované klienty",
"lan_encryption_mode_2": "Vyžadováno pro všechny klienty",
"lan_encryption_mode_desc": "Určuje, kdy bude šifrování použito při streamování přes místní síť. Šifrování může snížit výkon streamování, zejména u méně výkonných hostitelů a klientů.",
"locale": "Místní prostředí",
"locale_desc": "Místní jazyk používaný pro uživatelské rozhraní Sunshine.",
"locale_desc": "Lokální prostředí používané pro uživatelské rozhraní Sunshine.",
"log_level": "Úroveň logu",
"log_level_0": "Verbose",
"log_level_1": "Debug",
"log_level_2": "Info",
"log_level_3": "Varování",
"log_level_4": "Chyba",
"log_level_5": "Fatální",
"log_level_5": "Fatal",
"log_level_6": "Nic",
"log_level_desc": "Minimální úroveň logu vypisovado standardního výstupu",
"log_level_desc": "Minimální úroveň logu vytištěpro standardizaci",
"log_path": "Cesta k logu",
"log_path_desc": "Soubor, ve kterém jsou uloženy aktuální logy Sunshine.",
"log_path_desc": "Soubor s aktuálními protokoly sunshine jsou uloženy.",
"max_bitrate": "Maximální bitrate",
"max_bitrate_desc": "Maximální bitrate (v Kb/s), kterým bude Sunshine kódovat datový tok. Pokud je nastaven na 0, bude vždy použit bitrate požadovaný aplikací Moonlight.",
"min_threads": "Minimální počet vláken CPU",
"min_threads_desc": "Zvýšení této hodnoty mírně snižuje efektivitu kódování, ale tento kompromis se obvykle vyplatí, protože získáte více jader procesoru pro kódování. Ideální hodnota je nejnižší hodnota, která dokáže spolehlivě enkódovat při požadovaném nastavení streamování na vašem hardwaru.",
"max_bitrate_desc": "Maximální bitrate (v Kbps) zakódovaný sunshine streamem. Je-li nastaveno na 0, bude vždy používat bitrate požadovaný Moonlight.",
"min_threads": "Minimální počet CPU vláken",
"min_threads_desc": "Zvýšení hodnoty mírně snižuje efektivitu kódování, ale tento kompromis obvykle stojí za to získat více jader CPU pro kódování. Ideální hodnota je nejnižší hodnota, která že spolehlivě kódovat v požadovaném nastavení streamu do vašeho hardwaru.",
"misc": "Různé možnosti",
"motion_as_ds4": "Emulovat gamepad DS4, pokud klientský gamepad hlásí přítomnost pohybových senzorů",
"motion_as_ds4": "Emulovat DS4 gamepad pokud jsou přítomny snímače pohybu",
"motion_as_ds4_desc": "Je-li zakázáno, nebudou při výběru typu gamepadu brány v úvahu snímače pohybu.",
"mouse": "Povolit vstup myši",
"mouse_desc": "Umožňuje hostům ovládat systém pomocí myši",
@@ -313,52 +313,52 @@
"port_udp": "UDP",
"port_warning": "Vystavení webového uživatelského rozhraní na internet je bezpečnostní riziko! Pokračujte na vlastní nebezpečí!",
"port_web_ui": "Web UI",
"qp": "Kvantizační parametr",
"qp_desc": "Některá zařízení nemusí podporovat konstantní přenosovou rychlost. U těchto zařízení se místo toho používá QP. Vyšší hodnota znamená větší kompresi, ale nižší kvalitu.",
"qp": "Parametr kvantizace",
"qp_desc": "Některá zařízení nemusí podporovat Constant Bit Rate. Pro tato zařízení se místo toho používá QP. Vyšší hodnota znamená větší kompresi, ale menší kvalitu.",
"qsv_coder": "Kodér QuickSync (H264)",
"qsv_preset": "Předvolba QuickSync",
"qsv_preset_fast": "rychle (nízká kvalita)",
"qsv_preset": "QuickSync Preset",
"qsv_preset_fast": "rychlá (nízká kvalita)",
"qsv_preset_faster": "rychlejší (nižší kvalita)",
"qsv_preset_medium": "střední (výchozí)",
"qsv_preset_slow": "pomalý (dobrá kvalita)",
"qsv_preset_slower": "pomalejší (lepší kvalita)",
"qsv_preset_slowest": "nejpomalejší (nejlepší kvalita)",
"qsv_preset_veryfast": "nejrychlejší (nejnižší kvalita)",
"qsv_preset_veryfast": "nejrychlejší (nejnižší jakost)",
"qsv_slow_hevc": "Povolit pomalé kódování HEVC",
"qsv_slow_hevc_desc": "To může umožnit kódování HEVC na starších grafických procesorech Intel za cenu vyššího využití grafického procesoru a nižšího výkonu.",
"restart_note": "Sunshine se restartuje a aplikuje změny.",
"stream_audio": "Streamování zvuku",
"stream_audio_desc": "Zda se má zvuk streamovat, nebo ne. Vypnutí této funkce může být užitečné pro streamování bezhlavých displejů jako druhých monitorů.",
"sunshine_name": "Jméno Sunshine",
"sunshine_name_desc": "Název zobrazený u Moonlight. Pokud není zadán, použije se název hostitele počítače",
"sw_preset": "Předvolby SW",
"sw_preset_desc": "Optimalizace kompromisu mezi rychlostí kódování (zakódované snímky za sekundu) a účinností komprese (kvalita na bit v datovém toku). Výchozí hodnota je superrychlá.",
"qsv_slow_hevc_desc": "To může povolit HEVC kódování na starších Intel GPU, za cenu vyšší spotřeby GPU a horšího výkonu.",
"restart_note": "Sluneční brýle se restartuje a aplikuje změny.",
"stream_audio": "Stream zvuk",
"stream_audio_desc": "Zakázání zvuku může být užitečné pro streamování bezhlavých displejů jako druhý monitor.",
"sunshine_name": "Sluneční jméno",
"sunshine_name_desc": "Jméno zobrazené podle měsíčního světla. Není-li zadáno, použije se hostname počítače",
"sw_preset": "SW přednastavení",
"sw_preset_desc": "Optimalizujte kompromis mezi rychlostí kódování (kódované snímky za sekundu) a efektivitou komprese (kvalita na bit v bitovém toku). Výchozí nastavení je superrychlé.",
"sw_preset_fast": "rychlá",
"sw_preset_faster": "rychleji",
"sw_preset_medium": "střední",
"sw_preset_slow": "pomalu",
"sw_preset_slower": "pomalejší",
"sw_preset_superfast": "superrychlá (výchozí)",
"sw_preset_ultrafast": "ultrarychlá",
"sw_preset_veryfast": "velmirychlá",
"sw_preset_veryslow": "velmipomalá",
"sw_tune": "SW ladění",
"sw_tune_animation": "animace -- vhodné pro kreslené filmy; používá vyšší deblokaci a více referenčních snímků",
"sw_tune_desc": "Možnosti ladění, které se použijí po předvolbě. Výchozí hodnota je nulová latence.",
"sw_preset_superfast": "superfast (výchozí)",
"sw_preset_ultrafast": "ultrafast",
"sw_preset_veryfast": "veryfast",
"sw_preset_veryslow": "veryslow",
"sw_tune": "SW melodie",
"sw_tune_animation": "animace -- dobré pro karikatury; používá vyšší deblokovací a více referenčních rámců",
"sw_tune_desc": "Vyladění možností, které jsou aplikovány po předvolbě. Výchozí nastavení je nula.",
"sw_tune_fastdecode": "fastdecode -- umožňuje rychlejší dekódování vypnutím určitých filtrů",
"sw_tune_film": "film -- použití pro vysoce kvalitní filmový obsah; snižuje deblokaci",
"sw_tune_grain": "zrno - zachovává strukturu zrna ve starém zrnitém filmovém materiálu",
"sw_tune_stillimage": "stillimage -- dobré pro prezentační obsah",
"sw_tune_zerolatency": "zerolatency -- vhodné pro rychlé kódování a streamování s nízkou latencí (výchozí)",
"touchpad_as_ds4": "Emulovat gamepad DS4, pokud klientský gamepad hlásí přítomnost touchpadu",
"touchpad_as_ds4_desc": "Pokud je vypnuto, nebude při výběru typu gamepadu zohledněna přítomnost touchpadu.",
"sw_tune_film": "film -- použí pro vysoce kvalitní filmový obsah; snižuje odblokování",
"sw_tune_grain": "zrno zachovává strukturu zrn ve starém, zrním materiálu",
"sw_tune_stillimage": "stillimage -- dobré pro slideshow-like obsah",
"sw_tune_zerolatency": "nulová latence -- dobrá pro rychlé kódování a nízká latence streamování (výchozí)",
"touchpad_as_ds4": "Emulovat DS4 gamepad pokud klient nahlásí přítomnost touchpadu",
"touchpad_as_ds4_desc": "Je-li zakázáno, během výběru typu gamepadu nebude brána v úvahu přítomnost touchpadu.",
"upnp": "UPnP",
"upnp_desc": "Automatická konfigurace přesměrování portů pro streamování přes Internet",
"vaapi_strict_rc_buffer": "Přísné vynucení limitů datového toku snímků pro H.264/HEVC na grafických procesorech AMD",
"vaapi_strict_rc_buffer_desc": "Povolením této možnosti lze zabránit vypadávání snímků po síti při změnách scény, ale kvalita videa může být při pohybu snížena.",
"virtual_sink": "Virtuální zvuk",
"virtual_sink_desc": "Ručně zadejte virtuální zvukové zařízení, které chcete použít. Pokud není nastaveno, je zařízení vybráno automaticky. Důrazně doporučujeme ponechat toto pole prázdné, chcete-li použít automatický výběr zařízení!",
"virtual_sink_placeholder": "Streamovací reproduktory služby Steam",
"upnp_desc": "Automaticky konfigurovat přesměrování portů pro streamování přes Internet",
"vaapi_strict_rc_buffer": "Striktně prosazovat limity bitrate pro H.264/HEVC na AMD GPU.",
"vaapi_strict_rc_buffer_desc": "Povolením této volby se během změn scény vyhnete shození snímků přes síť, ale kvalita videa může být během pohybu snížena.",
"virtual_sink": "Virtuální šinek",
"virtual_sink_desc": "Ručně zadejte virtuální audio zařízení, které má být použito. Pokud je zařízení odstaveno, je vybráno automaticky. Důrazně doporučujeme ponechat toto pole prázdné pro automatický výběr zařízení!",
"virtual_sink_placeholder": "Reproduktory pro streamování přes Steam",
"vt_coder": "VideoToolbox Coder",
"vt_realtime": "Video Toolbox v reálném čase enkódování",
"vt_software": "Softwarové kódování video nástrojů",
@@ -422,34 +422,34 @@
"troubleshooting": {
"dd_reset": "Obnovit nastavení trvalého zobrazení zařízení",
"dd_reset_desc": "Pokud se sluneční svaz zasekne o obnovení změněného nastavení zobrazovacího zařízení, můžete obnovit nastavení a pokračovat v obnově stavu displeje ručně.",
"dd_reset_error": "Chyba při obnovení perzistence!",
"dd_reset_success": "Úspěch resetování perzistence!",
"dd_reset_error": "Chyba při obnovování trvalosti!",
"dd_reset_success": "Úspěch resetování trvalosti!",
"force_close": "Vynutit zavření",
"force_close_desc": "Pokud si aplikace Moonlight stěžuje na aktuálně spuštěnou aplikaci, mělo by její násilné zavření problém vyřešit.",
"force_close_desc": "Pokud si Měsíc stěžuje na právě spuštěnou aplikaci, vynucené zavření aplikace by mělo problém vyřešit.",
"force_close_error": "Chyba při zavírání aplikace",
"force_close_success": "Aplikace úspěšně uzavřena!",
"logs": "Logy",
"logs_desc": "Podívejte se na logy nahrané Sunshine",
"logs_find": "Hledat...",
"logs_desc": "Podívejte se na logy nahrané sunshine",
"logs_find": "Najít...",
"restart_sunshine": "Restartovat Sunshine",
"restart_sunshine_desc": "Pokud Sunshine nefunguje správně, můžete jej zkusit restartovat. Tím se ukončí všechny spuštěné relace.",
"restart_sunshine_desc": "Pokud sluneční svit nefunguje správně, můžete jej zkusit restartovat. To ukončí všechny spuštěné relace.",
"restart_sunshine_success": "Sunshine se restartuje",
"troubleshooting": "Řešení problémů",
"unpair_all": "Zrušit párování všech",
"unpair_all_error": "Chyba při odpárování",
"unpair_all_success": "Všechna zařízení jsou nespárovaná.",
"unpair_desc": "Odeberte spárovaná zařízení. Jednotlivá nespárovaná zařízení s aktivní relací zůstanou připojena, ale nemohou zahájit nebo obnovit relaci.",
"unpair_all": "Zrušit spárování vše",
"unpair_all_error": "Chyba při nepárování",
"unpair_all_success": "Všechna zařízení nejsou spárována.",
"unpair_desc": "Odstranit spárovaná zařízení. Jednotlivě nespárovaná zařízení s aktivní relací zůstanou připojena, ale nemohou spustit nebo obnovit relaci.",
"unpair_single_no_devices": "Neexistují žádná spárovaná zařízení.",
"unpair_single_success": "Zařízení však mohou být stále v aktivní relaci. Pomocí výše uvedeného tlačítka \"Vynutit ukončení\" ukončete všechny otevřené relace.",
"unpair_single_success": "Zařízení však mohou být stále v aktivní relaci. Použijte tlačítko 'Vynutit zavření' pro ukonče všech otevřených relací.",
"unpair_single_unknown": "Neznámý klient",
"unpair_title": "Zrušit párování"
},
"welcome": {
"confirm_password": "Potvrdit heslo",
"create_creds": "Před zahájením je třeba vytvořit nové uživatelské jméno a heslo pro přístup k webovému uživatelskému rozhraní.",
"create_creds_alert": "Pro přístup k webovému uživatelskému rozhraní Sunshine je třeba zadat níže uvedené přihlašovací údaje. Uchovávejte je v bezpečí, protože už je nikdy neuvidíte!",
"create_creds": "Před spuštěním potřebujeme, abyste vytvořili nové uživatelské jméno a heslo pro přístup k webovému uživatelskému rozhraní.",
"create_creds_alert": "Níže uvedené přihlašovací údaje jsou potřebné pro přístup k webovému rozhraní Sunshine. Uchovávejte je v bezpečí, protože je už nikdy nebudete vidět!",
"greeting": "Vítejte v Sunshine!",
"login": "Přihlásit se",
"welcome_success": "Tato stránka se brzy znovu načte a prohlížeč vás požádá o nové přihlašovací údaje"
"welcome_success": "Tato stránka se brzy obnoví, váš prohlížeč vás požádá o nové přihlašovací údaje."
}
}

View File

@@ -256,8 +256,6 @@
"log_path_desc": "The file where the current logs of Sunshine are stored.",
"max_bitrate": "Maximum Bitrate",
"max_bitrate_desc": "The maximum bitrate (in Kbps) that Sunshine will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
"minimum_fps_target": "Minimum FPS Target",
"minimum_fps_target_desc": "The lowest effective FPS a stream can reach. A value of 0 is treated as roughly half of the stream's FPS. A setting of 20 is recommended if you stream 24 or 30fps content.",
"min_threads": "Minimum CPU Thread Count",
"min_threads_desc": "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 desired streaming settings on your hardware.",
"misc": "Miscellaneous options",

View File

@@ -13,7 +13,7 @@
"elevated": "Come Admin",
"enabled": "Abilitato",
"enabled_def": "Abilitato (predefinito)",
"enabled_def_cbox": "Predefinito: selezionato",
"enabled_def_cbox": "Predefinito: controllato",
"error": "Errore!",
"note": "Nota:",
"password": "Password",
@@ -65,7 +65,7 @@
"env_vars_desc": "Tutti i comandi ottengono queste variabili d'ambiente per impostazione predefinita:",
"env_xrandr_example": "Esempio - Xrandr per l'automazione della risoluzione:",
"exit_timeout": "Timeout Uscita",
"exit_timeout_desc": "Numero di secondi in cui attendere che tutti i processi delle app si chiudano correttamente quando richiesto. Se disattivato, il valore predefinito è di 5 secondi. Se viene impostato a 0 o a un valore negativo, l'app verrà immediatamente terminata.",
"exit_timeout_desc": "Numero di secondi in cui attendere che tutti i processi delle app si chiudano correttamente quando richiesto. Se disattivato, il valore predefinito è di attendere fino a 5 secondi. Se impostato a zero o a un valore negativo, l'app verrà immediatamente terminata.",
"find_cover": "Trova Copertina",
"global_prep_desc": "Abilita/Disabilita l'esecuzione dei Comandi di Preparazione Globali per questa applicazione.",
"global_prep_name": "Comandi di Preparazione Globali",
@@ -159,15 +159,15 @@
"dd_config_revert_delay": "Ritardo ripristino configurazione",
"dd_config_revert_delay_desc": "Ulteriori ritardi in millisecondi per attendere prima di ripristinare la configurazione quando l'app è stata chiusa o l'ultima sessione è terminata. Lo scopo principale è quello di fornire una transizione più fluida quando si passa rapidamente tra le applicazioni.",
"dd_config_revert_on_disconnect": "Ripristina configurazione alla disconnessione",
"dd_config_revert_on_disconnect_desc": "Ripristina la configurazione al momento della disconnessione di tutti i client invece della chiusura dell'app o l'interruzione dell'ultima sessione.",
"dd_config_verify_only": "Verifica che il display sia abilitato",
"dd_config_revert_on_disconnect_desc": "Ripristina la configurazione al momento della disconnessione di tutti i client invece della chiusura dell'app o dell'ultima terminazione della sessione.",
"dd_config_verify_only": "Verifica che il display sia abilitato (predefinito)",
"dd_hdr_option": "HDR",
"dd_hdr_option_auto": "Attiva/disattiva la modalità HDR in base alle impostazioni del client (predefinito)",
"dd_hdr_option_auto": "Attiva/disattiva la modalità HDR come richiesto dal client (predefinito)",
"dd_hdr_option_disabled": "Non modificare le impostazioni HDR",
"dd_mode_remapping": "Modalità di visualizzazione remapping",
"dd_mode_remapping_add": "Aggiungi voce di remapping",
"dd_mode_remapping_desc_1": "Specificare le voci di rimappatura per modificare la risoluzione richiesta e/o la frequenza di aggiornamento ad altri valori.",
"dd_mode_remapping_desc_2": "L'elenco viene iterato dall'alto verso il basso e viene utilizzata la prima corrispondenza.",
"dd_mode_remapping_desc_1": "Specificare le voci di remapping per modificare la risoluzione richiesta e/o la frequenza di aggiornamento ad altri valori.",
"dd_mode_remapping_desc_2": "L'elenco è iterato dall'alto verso il basso e viene usata la prima partita.",
"dd_mode_remapping_desc_3": "I campi \"Richiesti\" possono essere lasciati vuoti per corrispondere a qualsiasi valore richiesto.",
"dd_mode_remapping_desc_4_final_values_mixed": "Almeno un campo \"Finale\" deve essere specificato. La risoluzione o la frequenza di aggiornamento non specificata non saranno modificate.",
"dd_mode_remapping_desc_4_final_values_non_mixed": "Il campo \"Finale\" deve essere specificato e non può essere vuoto.",
@@ -175,7 +175,7 @@
"dd_mode_remapping_desc_5_sops_resolution_only": "L'opzione \"Ottimizza le impostazioni di gioco\" deve essere abilitata nel client Moonlight, altrimenti la mappatura viene saltata.",
"dd_mode_remapping_final_refresh_rate": "Frequenza di aggiornamento finale",
"dd_mode_remapping_final_resolution": "Risoluzione finale",
"dd_mode_remapping_requested_fps": "FPS richiesti",
"dd_mode_remapping_requested_fps": "FPS Richiesto",
"dd_mode_remapping_requested_resolution": "Risoluzione richiesta",
"dd_options_header": "Opzioni avanzate del dispositivo di visualizzazione",
"dd_refresh_rate_option": "Velocità di aggiornamento",
@@ -189,9 +189,9 @@
"dd_resolution_option_manual": "Usa la risoluzione inserita manualmente",
"dd_resolution_option_manual_desc": "Inserisci la risoluzione da usare",
"dd_resolution_option_ogs_desc": "L'opzione \"Ottimizza le impostazioni di gioco\" deve essere abilitata sul client Moonlight perché questo funzioni.",
"dd_wa_hdr_toggle_delay_desc_1": "Quando si utilizza il dispositivo di visualizzazione virtuale (VDD) per lo streaming, potrebbe visualizzare erroneamente il colore HDR. Sunshine può cercare di mitigare questo problema, attivando e disattivando l'HDR.",
"dd_wa_hdr_toggle_delay_desc_2": "Se il valore è impostato a 0, il workaround è disabilitato (predefinito). Se il valore è compreso tra 0 e 3000 millisecondi, Sunshine disattiverà HDR, attenderà la quantità di tempo specificata e poi attiverà di nuovo l'HDR. Il tempo di ritardo raccomandato è di circa 500 millisecondi nella maggior parte dei casi.",
"dd_wa_hdr_toggle_delay_desc_3": "NON utilizzare questo workaround a meno che non si abbiano effettivamente problemi con HDR in quanto influisce direttamente sul tempo di inizio del flusso!",
"dd_wa_hdr_toggle_delay_desc_1": "Quando si utilizza il dispositivo di visualizzazione virtuale (VDD) per lo streaming, potrebbe visualizzare erroneamente il colore HDR. Sunshine può cercare di mitigare questo problema, spegnendo HDR e poi di nuovo.",
"dd_wa_hdr_toggle_delay_desc_2": "Se il valore è impostato a 0, il workaround è disabilitato (predefinito). Se il valore è compreso tra 0 e 3000 millisecondi, Sunshine disattiverà HDR, attendere la quantità di tempo specificata e poi accendere di nuovo l'HDR. Il tempo di ritardo raccomandato è di circa 500 millisecondi nella maggior parte dei casi.",
"dd_wa_hdr_toggle_delay_desc_3": "NON utilizzare questo workaround a meno che non si hanno effettivamente problemi con HDR in quanto influisce direttamente sul tempo di inizio del flusso!",
"dd_wa_hdr_toggle_delay": "Workaround ad alto contrasto per HDR",
"ds4_back_as_touchpad_click": "Mappa Indietro/Select come Clic Touchpad",
"ds4_back_as_touchpad_click_desc": "Quando si forza l'emulazione DS4, mappa Indietro/Select come Clic Touchpad",
@@ -211,7 +211,7 @@
"gamepad_auto": "Opzioni di selezione automatica",
"gamepad_desc": "Scegli quale tipo di gamepad emulare sull'host",
"gamepad_ds4": "DS4 (PS4)",
"gamepad_ds4_manual": "Opzioni del DS4",
"gamepad_ds4_manual": "Opzioni di selezione DS4",
"gamepad_ds5": "DS5 (PS5)",
"gamepad_switch": "Nintendo Pro (Switch)",
"gamepad_manual": "Opzioni manuali DS4",
@@ -294,9 +294,9 @@
"origin_web_ui_allowed_pc": "Solo localhost può accedere all'interfaccia Web",
"origin_web_ui_allowed_wan": "Chiunque può accedere all'interfaccia Web",
"output_name_desc_unix": "Durante l'avvio di Sunshine, dovresti vedere l'elenco dei display rilevati. Nota: devi usare il valore id all'interno della parentesi. Quello in basso è un esempio, la lista effettiva può essere trovata in \"Risoluzione dei Problemi\".",
"output_name_desc_windows": "Specifica manualmente un display id da usare per la cattura. Se lasciato vuoto, viene catturato il display primario. Nota: Se hai specificato una GPU sopra, questo display deve essere collegato a quella GPU. Durante l'avvio di Sunshine dovresti vedere la lista dei display individuati. Esempio sotto; l'output può essere trovato nella pagina di Troubleshooting.",
"output_name_desc_windows": "Specifica manualmente un display da usare per la cattura. Se lasciato vuoto, viene catturato il display primario. Nota: Se hai specificato una GPU sopra, questo display deve essere collegato a quella GPU. I valori appropriati possono essere trovati usando il seguente comando:",
"output_name_unix": "Numero di Display",
"output_name_windows": "Id display",
"output_name_windows": "Nome Output",
"ping_timeout": "Timeout Ping",
"ping_timeout_desc": "Per quanti millisecondi attendere dati da Moonlight prima di chiudere lo streaming",
"pkey": "Chiave Privata",
@@ -327,7 +327,7 @@
"qsv_slow_hevc": "Permetti la codifica lenta in HEVC",
"qsv_slow_hevc_desc": "Questo può abilitare la codifica HEVC su vecchie GPU Intel, al costo di un maggiore utilizzo della GPU e prestazioni peggiori.",
"restart_note": "Sunshine sta riavviando per applicare le modifiche.",
"stream_audio": "Stream Audio",
"stream_audio": "Audio Di Stream",
"stream_audio_desc": "Indica se trasmettere o meno audio. Disabilitarlo può essere utile per lo streaming di display senza intestazione come secondo monitor.",
"sunshine_name": "Nome Sunshine",
"sunshine_name_desc": "Il nome visualizzato da Moonlight. Se non specificato, viene utilizzato il nome host del PC",

View File

@@ -7,7 +7,7 @@
"cancel": "Скасувати",
"disabled": "Вимкнено",
"disabled_def": "Вимкнено (за замовчуванням)",
"disabled_def_cbox": "За замовчуванням: вимкнено",
"disabled_def_cbox": "За замовчуванням: відмічено",
"dismiss": "Відхилити",
"do_cmd": "Виконати команду",
"elevated": "Потребуються",

View File

@@ -27,8 +27,7 @@ for dir in ${DIRECTORIES}; do
# remove the directory if it is empty
if [[ $empty_dir != "" ]]; then # prevent the loop from running and failing if no directories found
# shellcheck disable=SC2066 # don't split words as we already know this will be a single directory
for i in "${empty_dir}"; do
for i in "${empty_dir}"; do # don't split words as we already know this will be a single directory
echo "Removing empty directory: ${i}"
rmdir "${i}"
done

View File

@@ -0,0 +1,64 @@
@echo off
setlocal enabledelayedexpansion
rem Check if a compatible version of ViGEmBus is already installed (1.17 or later)
rem
rem Note: We use exit code 2 to indicate success because either 0 or 1 may be returned
rem based on the PowerShell version if an exception occurs.
powershell -c Exit $(if ((Get-Item "$env:SystemRoot\System32\drivers\ViGEmBus.sys").VersionInfo.FileVersion -ge [System.Version]"1.17") { 2 } Else { 1 })
if %ERRORLEVEL% EQU 2 (
goto skip
)
goto continue
:skip
echo "The installed version is 1.17 or later, no update needed. Exiting."
exit /b 0
:continue
rem Get temp directory
set temp_dir=%temp%/Sunshine
rem Create temp directory if it doesn't exist
if not exist "%temp_dir%" mkdir "%temp_dir%"
rem Get system proxy setting
set proxy=
for /f "tokens=3" %%a in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" ^| find /i "ProxyEnable"') do (
set ProxyEnable=%%a
if !ProxyEnable! equ 0x1 (
for /f "tokens=3" %%a in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" ^| find /i "ProxyServer"') do (
set proxy=%%a
echo Using system proxy !proxy! to download Virtual Gamepad
set proxy=-x !proxy!
)
) else (
rem Proxy is not enabled.
)
)
rem get browser_download_url from asset 0 of https://api.github.com/repos/nefarius/vigembus/releases/latest
set latest_release_url=https://api.github.com/repos/nefarius/vigembus/releases/latest
rem Use curl to get the api response, and find the browser_download_url
for /F "tokens=* USEBACKQ" %%F in (`curl -s !proxy! -L %latest_release_url% ^| findstr browser_download_url`) do (
set browser_download_url=%%F
)
rem Strip quotes
set browser_download_url=%browser_download_url:"=%
rem Remove the browser_download_url key
set browser_download_url=%browser_download_url:browser_download_url: =%
echo %browser_download_url%
rem Download the exe
curl -s -L !proxy! -o "%temp_dir%\virtual_gamepad.exe" %browser_download_url%
rem Install Virtual Gamepad
%temp_dir%\virtual_gamepad.exe /passive /promptrestart
rem Delete temp directory
rmdir /S /Q "%temp_dir%"

View File

@@ -1,20 +0,0 @@
# Check if a compatible version of ViGEmBus is already installed (1.17 or later)
try {
$vigemBusPath = "$env:SystemRoot\System32\drivers\ViGEmBus.sys"
$fileVersion = (Get-Item $vigemBusPath).VersionInfo.FileVersion
if ($fileVersion -ge [System.Version]"1.17") {
Write-Information "The installed version is 1.17 or later, no update needed. Exiting."
exit 0
}
}
catch {
Write-Information "ViGEmBus driver not found or inaccessible, proceeding with installation."
}
# Install Virtual Gamepad
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
$installerPath = Join-Path $scriptPath "vigembus_installer.exe"
Start-Process `
-FilePath $installerPath `
-ArgumentList "/passive", "/promptrestart"

View File

@@ -0,0 +1,4 @@
@echo off
rem Use wmic to get the uninstall Virtual Gamepad
wmic product where name="ViGEm Bus Driver" call uninstall

View File

@@ -1,8 +0,0 @@
# Use Get-CimInstance to find and uninstall Virtual Gamepad
$product = Get-CimInstance -ClassName Win32_Product -Filter "Name='ViGEm Bus Driver'"
if ($product) {
Invoke-CimMethod -InputObject $product -MethodName Uninstall
Write-Information "ViGEm Bus Driver uninstalled successfully"
} else {
Write-Warning "ViGEm Bus Driver not found"
}

View File

@@ -56,7 +56,7 @@ foreach(dep ${SUNSHINE_TARGET_DEPENDENCIES})
add_dependencies(${PROJECT_NAME} ${dep}) # compile these before sunshine
endforeach()
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20)
target_link_libraries(${PROJECT_NAME}
${SUNSHINE_EXTERNAL_LIBRARIES}
gtest

View File

@@ -4,7 +4,6 @@
*/
#include "../tests_common.h"
#include <format>
#include <src/config.h>
#include <src/display_device.h>
#include <src/rtsp.h>
@@ -474,7 +473,7 @@ namespace {
} else {
const auto [manual_res] = std::get<manual_value_t<res_t>>(input_res);
video_config.dd.resolution_option = manual;
video_config.dd.manual_resolution = std::format("{}x{}", static_cast<int>(manual_res.m_width), static_cast<int>(manual_res.m_height));
video_config.dd.manual_resolution = std::to_string(manual_res.m_width) + "x"s + std::to_string(manual_res.m_height);
}
}

Some files were not shown because too many files have changed in this diff Show More