mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd0f9a4508 | |||
| fc7b9e30c8 | |||
| dbe80d0f92 | |||
| a28c20df18 | |||
| 4503fea7fb | |||
| 03bb53d591 | |||
| bb6e3bc8e1 | |||
| b2d3ded6f4 | |||
| 9f101fb546 | |||
| 48c2c52498 | |||
| d6787c4ed4 | |||
| eff88de993 | |||
| b3ee60d422 | |||
| 99cf9ac960 |
+2
-3
@@ -1,6 +1,5 @@
|
||||
# ensure dockerfiles are checked out with LF line endings
|
||||
# ensure Linux specific files are checked out with LF line endings
|
||||
Dockerfile text eol=lf
|
||||
*.dockerfile text eol=lf
|
||||
|
||||
# ensure flatpak lint json files are checked out with LF line endings
|
||||
*flatpak-lint-*.json text eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "copr-ci-gcc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^/?(?:[^/]+/){5}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "docker-gcc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(?:#\\d+\\s+\\d+\\.\\d+\\s+)?/?(?:[^/]+/){2}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "gcc-strip3",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^/?(?:[^/]+/){3}([^:]+):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "gcc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"owner": "doxygen",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^.*?([A-Za-z]:[\\\\/][^:]+|[\\\\/][^:]+):(\\d+): ([a-zA-Z]+): (.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -20,4 +20,6 @@ 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 }}
|
||||
|
||||
@@ -26,4 +26,6 @@ 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 }}
|
||||
|
||||
@@ -26,4 +26,6 @@ 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 }}
|
||||
|
||||
@@ -16,6 +16,10 @@ on:
|
||||
required: false
|
||||
COPR_CLI_CONFIG:
|
||||
required: false
|
||||
GH_BOT_TOKEN:
|
||||
required: false
|
||||
VIRUSTOTAL_API_KEY:
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: "_${{ github.workflow }}-${{ github.ref }}"
|
||||
@@ -45,7 +49,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: build-*
|
||||
|
||||
@@ -73,15 +73,16 @@ 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
|
||||
|
||||
@@ -101,9 +102,11 @@ jobs:
|
||||
flatpak-${{ matrix.arch }}-
|
||||
|
||||
- name: Configure Flatpak Manifest
|
||||
env:
|
||||
BRANCH: ${{ github.head_ref }}
|
||||
run: |
|
||||
# variables for manifest
|
||||
branch="${{ github.head_ref }}"
|
||||
branch="${{ env.BRANCH }}"
|
||||
build_version=${{ inputs.release_version }}
|
||||
commit=${{ inputs.release_commit }}
|
||||
|
||||
@@ -137,19 +140,20 @@ 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: |
|
||||
sudo su $(whoami) -c "flatpak run org.flatpak.Builder \
|
||||
echo "::add-matcher::.github/matchers/gcc-strip3.json"
|
||||
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 \
|
||||
@@ -157,15 +161,16 @@ 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
|
||||
@@ -177,7 +182,7 @@ jobs:
|
||||
--exceptions \
|
||||
--user-exceptions "${exceptions_file}" \
|
||||
manifest \
|
||||
${APP_ID}.yml
|
||||
"${APP_ID}.yml"
|
||||
|
||||
echo "Linting flatpak repo"
|
||||
# TODO: add arg
|
||||
@@ -193,13 +198,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
|
||||
|
||||
@@ -36,8 +36,6 @@ 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"
|
||||
@@ -73,9 +71,13 @@ 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="${{ github.head_ref }}"
|
||||
branch="${{ env.HEAD_REF }}"
|
||||
build_version=${{ inputs.release_version }}
|
||||
commit=${{ inputs.release_commit }}
|
||||
|
||||
@@ -96,9 +98,9 @@ jobs:
|
||||
else
|
||||
echo "This is a PR event"
|
||||
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
|
||||
branch="${{ github.event.pull_request.head.ref }}"
|
||||
default_branch="${{ github.event.pull_request.head.repo.default_branch }}"
|
||||
tag="${{ github.event.pull_request.head.ref }}"
|
||||
branch="${{ env.PR_HEAD_REF }}"
|
||||
default_branch="${{ env.PR_DEFAULT_BRANCH }}"
|
||||
tag="${{ env.PR_HEAD_REF }}"
|
||||
fi
|
||||
echo "Branch: ${branch}"
|
||||
echo "Clone URL: ${clone_url}"
|
||||
@@ -143,8 +145,9 @@ 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
|
||||
@@ -156,6 +159,7 @@ jobs:
|
||||
publish: false
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
validate: true
|
||||
- run: echo "::remove-matcher owner=gcc-strip3::"
|
||||
|
||||
- name: Setup python
|
||||
id: python
|
||||
|
||||
@@ -79,8 +79,8 @@ jobs:
|
||||
--enable-x11 \
|
||||
--enable-glx \
|
||||
--enable-wayland \
|
||||
--without-legacy # emgd, nvctrl, fglrx
|
||||
make -j $(nproc)
|
||||
--without-legacy
|
||||
make -j "$(nproc)"
|
||||
sudo make install
|
||||
cd .. && rm -rf libva-*
|
||||
|
||||
@@ -91,6 +91,7 @@ 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' \
|
||||
@@ -98,12 +99,13 @@ 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'
|
||||
|
||||
@@ -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[@]}"
|
||||
@@ -251,7 +251,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,7 +272,9 @@ 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}
|
||||
|
||||
@@ -56,6 +56,7 @@ jobs:
|
||||
uses: LizardByte/.github/.github/workflows/__call-docker.yml@master
|
||||
with:
|
||||
maximize_build_space: true
|
||||
maximize_build_space_root_reserve_size: 28672
|
||||
publish_release: ${{ needs.release-setup.outputs.publish_release }}
|
||||
release_commit: ${{ needs.release-setup.outputs.release_commit }}
|
||||
release_tag: ${{ needs.release-setup.outputs.release_tag }}
|
||||
@@ -136,8 +137,6 @@ jobs:
|
||||
include:
|
||||
- name: Linux-AppImage
|
||||
coverage: true
|
||||
- name: Homebrew-macos-13
|
||||
coverage: false
|
||||
- name: Homebrew-macos-14
|
||||
coverage: false
|
||||
- name: Homebrew-macos-15
|
||||
@@ -151,7 +150,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download coverage artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: coverage-${{ matrix.name }}
|
||||
path: _coverage
|
||||
@@ -192,7 +191,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: build-*
|
||||
@@ -225,7 +224,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download homebrew artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: beta-Homebrew
|
||||
path: homebrew
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: 13+</td>
|
||||
<td>macOS: 14+</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux/Debian: 12+ (bookworm)</td>
|
||||
<td>Linux/Debian: 13+ (trixie)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux/Fedora: 40+</td>
|
||||
<td>Linux/Fedora: 41+</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux/Ubuntu: 22.04+ (jammy)</td>
|
||||
|
||||
@@ -45,6 +45,7 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "\
|
||||
libcap2, \
|
||||
libcurl4, \
|
||||
libdrm2, \
|
||||
libgbm1, \
|
||||
libevdev2, \
|
||||
libnuma1, \
|
||||
libopus0, \
|
||||
@@ -65,6 +66,7 @@ set(CPACK_RPM_PACKAGE_REQUIRES "\
|
||||
libva >= 2.14.0, \
|
||||
libwayland-client >= 1.20.0, \
|
||||
libX11 >= 1.7.3.1, \
|
||||
mesa-libgbm >= 25.0.7, \
|
||||
miniupnpc >= 2.2.4, \
|
||||
numactl-libs >= 2.0.14, \
|
||||
openssl >= 3.0.2, \
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Set build variables if env variables are defined
|
||||
# These are used in configured files such as manifests for different packages
|
||||
if(DEFINED ENV{BRANCH}) # cmake-lint: disable=W0106
|
||||
if(DEFINED ENV{BRANCH})
|
||||
set(GITHUB_BRANCH $ENV{BRANCH})
|
||||
endif()
|
||||
if(DEFINED ENV{BUILD_VERSION}) # cmake-lint: disable=W0106
|
||||
set(BUILD_VERSION $ENV{BUILD_VERSION})
|
||||
endif()
|
||||
if(DEFINED ENV{CLONE_URL}) # cmake-lint: disable=W0106
|
||||
if(DEFINED ENV{CLONE_URL})
|
||||
set(GITHUB_CLONE_URL $ENV{CLONE_URL})
|
||||
endif()
|
||||
if(DEFINED ENV{COMMIT}) # cmake-lint: disable=W0106
|
||||
if(DEFINED ENV{COMMIT})
|
||||
set(GITHUB_COMMIT $ENV{COMMIT})
|
||||
endif()
|
||||
if(DEFINED ENV{TAG}) # cmake-lint: disable=W0106
|
||||
if(DEFINED ENV{TAG})
|
||||
set(GITHUB_TAG $ENV{TAG})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ ENV CLONE_URL=${CLONE_URL}
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# hadolint ignore=SC2016
|
||||
RUN <<_SETUP
|
||||
#!/bin/bash
|
||||
set -e
|
||||
@@ -42,6 +41,7 @@ useradd -m builder
|
||||
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
|
||||
|
||||
# patch the build flags
|
||||
# shellcheck disable=SC2016
|
||||
sed -i 's,#MAKEFLAGS="-j2",MAKEFLAGS="-j$(nproc)",g' /etc/makepkg.conf
|
||||
|
||||
# install dependencies
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# platforms: linux/amd64
|
||||
# platforms_pr: linux/amd64
|
||||
# no-cache-filters: toolchain-base,toolchain
|
||||
ARG BASE=ubuntu
|
||||
ARG TAG=22.04
|
||||
ARG BASE=debian
|
||||
ARG TAG=trixie-slim
|
||||
FROM ${BASE}:${TAG} AS toolchain-base
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -19,18 +19,17 @@ 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.22.* \
|
||||
cmake=3.31.* \
|
||||
ca-certificates \
|
||||
doxygen \
|
||||
gcc=4:11.2.* \
|
||||
g++=4:11.2.* \
|
||||
gcc=4:14.2.* \
|
||||
g++=4:14.2.* \
|
||||
gdb \
|
||||
git \
|
||||
graphviz \
|
||||
@@ -60,21 +59,13 @@ 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="11.8.0"
|
||||
ENV CUDA_BUILD="520.61.05"
|
||||
# hadolint ignore=SC3010
|
||||
ENV CUDA_VERSION="12.9.1"
|
||||
ENV CUDA_BUILD="575.57.08"
|
||||
RUN <<_INSTALL_CUDA
|
||||
#!/bin/bash
|
||||
set -e
|
||||
@@ -85,18 +76,31 @@ 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}"
|
||||
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
|
||||
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}"
|
||||
_INSTALL_CUDA
|
||||
|
||||
WORKDIR /
|
||||
# Write a shell script that starts Xvfb and then runs a shell
|
||||
# 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
|
||||
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
|
||||
@@ -107,11 +111,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 ["/entrypoint.sh"]
|
||||
ENTRYPOINT ["/toolchain/entrypoint.sh"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# platforms_pr: linux/amd64
|
||||
# no-cache-filters: sunshine-base,artifacts,sunshine
|
||||
ARG BASE=debian
|
||||
ARG TAG=bookworm
|
||||
ARG TAG=trixie
|
||||
FROM ${BASE}:${TAG} AS sunshine-base
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -32,6 +32,7 @@ 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' \
|
||||
@@ -42,7 +43,6 @@ _BUILD
|
||||
|
||||
# run tests
|
||||
WORKDIR /build/sunshine/build/tests
|
||||
# hadolint ignore=SC1091
|
||||
RUN <<_TEST
|
||||
#!/bin/bash
|
||||
set -e
|
||||
@@ -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
|
||||
--sudo-off \
|
||||
--ubuntu-test-repo
|
||||
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
|
||||
|
||||
@@ -42,7 +42,6 @@ _BUILD
|
||||
|
||||
# run tests
|
||||
WORKDIR /build/sunshine/build/tests
|
||||
# hadolint ignore=SC1091
|
||||
RUN <<_TEST
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
+10
-1
@@ -3,6 +3,15 @@ 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
|
||||
@@ -16,7 +25,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 ~11.8.
|
||||
At the time of writing, the recommended version to use is CUDA ~12.9.
|
||||
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
|
||||
|
||||
+31
-5
@@ -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,6 +1371,32 @@ 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
|
||||
|
||||
+8
-15
@@ -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="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 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>sunshine.AppImage</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -55,27 +55,18 @@ need to install CUDA.}
|
||||
<td>sunshine-ubuntu-24.04-{arch}.deb</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
<td>sunshine-debian-trixie-{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>
|
||||
@@ -89,13 +80,15 @@ 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
|
||||
- ✖ CentOS 7
|
||||
- ✖ Rocky Linux 8
|
||||
- ✖ Rocky Linux 9
|
||||
|
||||
##### Install
|
||||
1. Download [sunshine.AppImage](https://github.com/LizardByte/Sunshine/releases/latest/download/sunshine.AppImage)
|
||||
|
||||
+28
-2
@@ -84,9 +84,35 @@ client only 1 Gbit/s or Wi-Fi. Similarly, a 1 Gbps host may be too fast for a
|
||||
client having only a 100 Mbps interface.
|
||||
|
||||
As a workaround the transmission speed of the host NIC can be reduced: 1 Gbps
|
||||
instead of 2.5 or 100 Mbps instead of 1 Gbps. (A technically more advanced
|
||||
instead of 2.5 or 100 Mbps instead of 1 Gbps. A technically more advanced
|
||||
solution would be to configure traffic shaping rules at the OS-level, so that
|
||||
only Sunshine's traffic is slowed down.)
|
||||
only Sunshine's traffic is slowed down.
|
||||
|
||||
Such a solution on Linux could look like that:
|
||||
|
||||
```bash
|
||||
# 1) Remove existing qdisc (pfifo_fast)
|
||||
sudo tc qdisc del dev <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.
|
||||
|
||||
Sunshine versions > 0.23.1 include improved networking code that should
|
||||
alleviate or even solve this issue (without reducing the NIC speed).
|
||||
|
||||
@@ -56,18 +56,18 @@ BuildRequires: which
|
||||
BuildRequires: xorg-x11-server-Xvfb
|
||||
|
||||
# Conditional BuildRequires for cuda-gcc based on Fedora version
|
||||
%if 0%{?fedora} >= 40 && 0%{?fedora} <= 41
|
||||
%if 0%{?fedora} <= 41
|
||||
BuildRequires: gcc13
|
||||
BuildRequires: gcc13-c++
|
||||
%global gcc_version 13
|
||||
%global cuda_version 12.6.3
|
||||
%global cuda_build 560.35.05
|
||||
%global cuda_version 12.9.1
|
||||
%global cuda_build 575.57.08
|
||||
%elif %{?fedora} >= 42
|
||||
BuildRequires: gcc14
|
||||
BuildRequires: gcc14-c++
|
||||
%global gcc_version 14
|
||||
%global cuda_version 12.8.1
|
||||
%global cuda_build 570.124.06
|
||||
%global cuda_version 12.9.1
|
||||
%global cuda_build 575.57.08
|
||||
%endif
|
||||
|
||||
%global cuda_dir %{_builddir}/cuda
|
||||
@@ -97,9 +97,6 @@ tar -xzf %{SOURCE0} -C %{_builddir}/Sunshine
|
||||
# list directory
|
||||
ls -a %{_builddir}/Sunshine
|
||||
|
||||
# patches
|
||||
%autopatch -p1
|
||||
|
||||
%build
|
||||
# exit on error
|
||||
set -e
|
||||
@@ -174,7 +171,7 @@ function install_cuda() {
|
||||
--backup \
|
||||
--directory="%{cuda_dir}" \
|
||||
--verbose \
|
||||
< "%{_builddir}/Sunshine/packaging/linux/fedora/patches/f42/${architecture}/01-math_functions.patch"
|
||||
< "%{_builddir}/Sunshine/packaging/linux/patches/${architecture}/01-math_functions.patch"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Submodule packaging/linux/flatpak/deps/flatpak-builder-tools updated: 7090720d43...d2fa57ab89
@@ -19,8 +19,8 @@
|
||||
"only-arches": [
|
||||
"x86_64"
|
||||
],
|
||||
"url": "https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda_12.6.2_560.35.03_linux.run",
|
||||
"sha256": "3729a89cb58f7ca6a46719cff110d6292aec7577585a8d71340f0dbac54fb237",
|
||||
"url": "https://developer.download.nvidia.com/compute/cuda/12.9.1/local_installers/cuda_12.9.1_575.57.08_linux.run",
|
||||
"sha256": "0f6d806ddd87230d2adbe8a6006a9d20144fdbda9de2d6acc677daa5d036417a",
|
||||
"dest-filename": "cuda.run"
|
||||
},
|
||||
{
|
||||
@@ -28,8 +28,8 @@
|
||||
"only-arches": [
|
||||
"aarch64"
|
||||
],
|
||||
"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",
|
||||
"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",
|
||||
"dest-filename": "cuda.run"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -37,6 +37,10 @@ class @PROJECT_NAME@ < Formula
|
||||
depends_on "opus"
|
||||
depends_on "icu4c" => :recommended
|
||||
|
||||
on_macos do
|
||||
depends_on xcode: ["15.3", :build]
|
||||
end
|
||||
|
||||
on_linux do
|
||||
depends_on "avahi"
|
||||
depends_on "libayatana-appindicator"
|
||||
@@ -59,6 +63,16 @@ class @PROJECT_NAME@ < Formula
|
||||
depends_on "wayland"
|
||||
end
|
||||
|
||||
fails_with :clang do
|
||||
build 1400
|
||||
cause "Requires C++23 support"
|
||||
end
|
||||
|
||||
fails_with :gcc do
|
||||
version "12" # fails with GCC 12.x and earlier
|
||||
cause "Requires C++23 support"
|
||||
end
|
||||
|
||||
def install
|
||||
ENV["BRANCH"] = "@GITHUB_BRANCH@"
|
||||
ENV["BUILD_VERSION"] = "@BUILD_VERSION@"
|
||||
|
||||
@@ -1,61 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
if ! [ -x "$(command -v ./go-png2ico)" ]; then
|
||||
echo "./go-png2ico not found"
|
||||
echo "download the executable from https://github.com/J-Siu/go-png2ico"
|
||||
echo "and drop it in this folder"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v ./oxipng)" ]; then
|
||||
echo "./oxipng executable not found"
|
||||
echo "download the executable from https://github.com/shssoichiro/oxipng"
|
||||
echo "and drop it in this folder"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v inkscape)" ]; then
|
||||
echo "inkscape executable not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
icon_base_sizes=(16 64)
|
||||
icon_sizes_keys=() # associative array to prevent duplicates
|
||||
icon_sizes_keys[256]=1
|
||||
|
||||
for icon_base_size in ${icon_base_sizes[@]}; do
|
||||
# increment in 25% till 400%
|
||||
icon_size_increment=$((icon_base_size / 4))
|
||||
for ((i = 0; i <= 12; i++)); do
|
||||
icon_sizes_keys[$((icon_base_size + i * icon_size_increment))]=1
|
||||
done
|
||||
done
|
||||
|
||||
# convert to normal array
|
||||
icon_sizes=${!icon_sizes_keys[@]}
|
||||
|
||||
echo "using icon sizes:"
|
||||
echo ${icon_sizes[@]}
|
||||
|
||||
src_vectors=("../../src_assets/common/assets/web/public/images/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
|
||||
#!/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
|
||||
|
||||
+58
-30
@@ -3,6 +3,7 @@ set -e
|
||||
|
||||
# Default value for arguments
|
||||
appimage_build=0
|
||||
cuda_patches=0
|
||||
num_processors=$(nproc)
|
||||
publisher_name="Third Party Publisher"
|
||||
publisher_website=""
|
||||
@@ -28,6 +29,7 @@ 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.
|
||||
@@ -55,6 +57,9 @@ while getopts ":hs-:" opt; do
|
||||
appimage_build=1
|
||||
skip_libva=1
|
||||
;;
|
||||
cuda-patches)
|
||||
cuda_patches=1
|
||||
;;
|
||||
num-processors=*)
|
||||
num_processors="${OPTARG#*=}"
|
||||
;;
|
||||
@@ -185,7 +190,15 @@ 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"
|
||||
@@ -193,11 +206,7 @@ function add_debian_deps() {
|
||||
}
|
||||
|
||||
function add_ubuntu_deps() {
|
||||
if [ "$ubuntu_test_repo" == 1 ]; then
|
||||
# allow newer gcc
|
||||
${sudo_cmd} add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
fi
|
||||
|
||||
add_test_ppa
|
||||
add_debian_based_deps
|
||||
dependencies+=(
|
||||
"libappindicator3-dev"
|
||||
@@ -298,6 +307,24 @@ 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() {
|
||||
@@ -460,6 +487,8 @@ function run_install() {
|
||||
nvm_url="https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh"
|
||||
echo "nvm url: ${nvm_url}"
|
||||
wget -qO- ${nvm_url} | bash
|
||||
|
||||
# shellcheck source=/dev/null # we don't care that shellcheck cannot find nvm.sh
|
||||
source "$HOME/.nvm/nvm.sh"
|
||||
nvm install node
|
||||
nvm use node
|
||||
@@ -534,27 +563,26 @@ 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.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
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="13"
|
||||
nvm_node=0
|
||||
dev_tools_group="Development Tools"
|
||||
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
|
||||
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.6.3
|
||||
cuda_build=560.35.05
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="13"
|
||||
nvm_node=0
|
||||
dev_tools_group="development-tools"
|
||||
@@ -563,8 +591,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.8.1
|
||||
cuda_build=570.124.06
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="14"
|
||||
nvm_node=0
|
||||
dev_tools_group="development-tools"
|
||||
@@ -573,27 +601,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="11.8.0"
|
||||
cuda_build="520.61.05"
|
||||
gcc_version="11"
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="13"
|
||||
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="11.8.0"
|
||||
cuda_build="520.61.05"
|
||||
gcc_version="11"
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="14"
|
||||
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="11.8.0"
|
||||
cuda_build="520.61.05"
|
||||
gcc_version="11"
|
||||
cuda_version="12.9.1"
|
||||
cuda_build="575.57.08"
|
||||
gcc_version="14"
|
||||
nvm_node=0
|
||||
else
|
||||
echo "Unsupported Distro or Version"
|
||||
|
||||
+4
-2
@@ -504,7 +504,8 @@ namespace config {
|
||||
{} // wa
|
||||
}, // display_device
|
||||
|
||||
0 // max_bitrate
|
||||
0, // max_bitrate
|
||||
0 // minimum_fps_target (0 = framerate)
|
||||
};
|
||||
|
||||
audio_t audio {
|
||||
@@ -1146,6 +1147,7 @@ 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);
|
||||
@@ -1419,7 +1421,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(NULL, executable, ARRAYSIZE(executable));
|
||||
GetModuleFileNameW(nullptr, executable, ARRAYSIZE(executable));
|
||||
|
||||
SHELLEXECUTEINFOW shell_exec_info {};
|
||||
shell_exec_info.cbSize = sizeof(shell_exec_info);
|
||||
|
||||
@@ -141,6 +141,7 @@ namespace config {
|
||||
} dd;
|
||||
|
||||
int max_bitrate; // Maximum bitrate, sets ceiling in kbps for bitrate requested from client
|
||||
double minimum_fps_target; ///< Lowest framerate that will be used when streaming. Range 0-1000, 0 = half of client's requested framerate.
|
||||
};
|
||||
|
||||
struct audio_t {
|
||||
|
||||
+3
-2
@@ -8,6 +8,7 @@
|
||||
|
||||
// standard includes
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
@@ -713,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 = "'index' out of range, max index is "s + std::to_string(max_index);
|
||||
error = std::format("'index' {} out of range, max index is {}", index, max_index);
|
||||
}
|
||||
bad_request(response, request, error);
|
||||
return;
|
||||
@@ -730,7 +731,7 @@ namespace confighttp {
|
||||
proc::refresh(config::stream.file_apps);
|
||||
|
||||
output_tree["status"] = true;
|
||||
output_tree["result"] = "application " + std::to_string(index) + " deleted";
|
||||
output_tree["result"] = std::format("application {} deleted", index);
|
||||
send_response(response, output_tree);
|
||||
} catch (std::exception &e) {
|
||||
BOOST_LOG(warning) << "DeleteApp: "sv << e.what();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
// standard includes
|
||||
#include <csignal>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
@@ -25,13 +26,11 @@ extern "C" {
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
platf::open_url(url);
|
||||
}
|
||||
|
||||
@@ -192,8 +191,8 @@ namespace service_ctrl {
|
||||
}
|
||||
|
||||
private:
|
||||
SC_HANDLE scm_handle = NULL;
|
||||
SC_HANDLE service_handle = NULL;
|
||||
SC_HANDLE scm_handle = nullptr;
|
||||
SC_HANDLE service_handle = nullptr;
|
||||
};
|
||||
|
||||
bool is_service_running() {
|
||||
|
||||
+3
-9
@@ -14,19 +14,13 @@
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @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);
|
||||
void launch_ui(const std::optional<std::string> &path = std::nullopt);
|
||||
|
||||
/**
|
||||
* @brief Functions for handling command line arguments.
|
||||
|
||||
+1
-1
@@ -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(NULL);
|
||||
session_monitor_hwnd_promise.set_value(nullptr);
|
||||
BOOST_LOG(error) << "Failed to register session monitor window class"sv << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
// this include
|
||||
#include "nvenc_base.h"
|
||||
|
||||
// standard includes
|
||||
#include <format>
|
||||
|
||||
// local includes
|
||||
#include "src/config.h"
|
||||
#include "src/logging.h"
|
||||
@@ -427,7 +430,7 @@ namespace nvenc {
|
||||
extra += " two-pass";
|
||||
}
|
||||
if (config.vbv_percentage_increase > 0 && get_encoder_cap(NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE)) {
|
||||
extra += " vbv+" + std::to_string(config.vbv_percentage_increase);
|
||||
extra += std::format(" vbv+{}", config.vbv_percentage_increase);
|
||||
}
|
||||
if (encoder_params.rfi) {
|
||||
extra += " rfi";
|
||||
@@ -439,7 +442,7 @@ namespace nvenc {
|
||||
extra += " spatial-aq";
|
||||
}
|
||||
if (enc_config.rcParams.enableMinQP) {
|
||||
extra += " qpmin=" + std::to_string(enc_config.rcParams.minQP.qpInterP);
|
||||
extra += std::format(" qpmin={}", enc_config.rcParams.minQP.qpInterP);
|
||||
}
|
||||
if (config.insert_filler_data) {
|
||||
extra += " filler-data";
|
||||
|
||||
@@ -12,13 +12,13 @@ namespace nvenc {
|
||||
|
||||
nvenc_d3d11::nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type):
|
||||
nvenc_base(device_type) {
|
||||
async_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
async_event_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
}
|
||||
|
||||
nvenc_d3d11::~nvenc_d3d11() {
|
||||
if (dll) {
|
||||
FreeLibrary(dll);
|
||||
dll = NULL;
|
||||
dll = nullptr;
|
||||
}
|
||||
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, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
|
||||
if ((dll = LoadLibraryEx(dll_name, nullptr, 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 = NULL;
|
||||
dll = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace nvenc {
|
||||
bool wait_for_async_event(uint32_t timeout_ms) override;
|
||||
|
||||
private:
|
||||
HMODULE dll = NULL;
|
||||
HMODULE dll = nullptr;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace nvenc {
|
||||
|
||||
constexpr auto dll_name = "nvcuda.dll";
|
||||
|
||||
if ((cuda_functions.dll = LoadLibraryEx(dll_name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
|
||||
if ((cuda_functions.dll = LoadLibraryEx(dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
|
||||
auto load_function = [&]<typename T>(T &location, auto symbol) -> bool {
|
||||
location = (T) GetProcAddress(cuda_functions.dll, symbol);
|
||||
return location != nullptr;
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace nvenc {
|
||||
|
||||
autopop_context push_context();
|
||||
|
||||
HMODULE dll = NULL;
|
||||
HMODULE dll = nullptr;
|
||||
const ID3D11DevicePtr d3d_device;
|
||||
ID3D11Texture2DPtr d3d_input_texture;
|
||||
|
||||
|
||||
+21
-4
@@ -7,6 +7,7 @@
|
||||
|
||||
// standard includes
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -154,7 +155,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 != NULL) {
|
||||
if (default_value != nullptr) {
|
||||
return std::string(default_value);
|
||||
}
|
||||
|
||||
@@ -636,7 +637,7 @@ namespace nvhttp {
|
||||
tree.put("root.<xmlattr>.status_code", 400);
|
||||
tree.put(
|
||||
"root.<xmlattr>.status_message",
|
||||
"Pin must be 4 digits, " + std::to_string(pin.size()) + " provided"
|
||||
std::format("Pin must be 4 digits, {} provided", pin.size())
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -896,7 +897,15 @@ namespace nvhttp {
|
||||
}
|
||||
|
||||
tree.put("root.<xmlattr>.status_code", 200);
|
||||
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.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.gamesession", 1);
|
||||
|
||||
rtsp_stream::launch_session_raise(launch_session);
|
||||
@@ -978,7 +987,15 @@ namespace nvhttp {
|
||||
}
|
||||
|
||||
tree.put("root.<xmlattr>.status_code", 200);
|
||||
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.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.resume", 1);
|
||||
|
||||
rtsp_stream::launch_session_raise(launch_session);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
// standard includes
|
||||
#include <fcntl.h>
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -574,7 +575,7 @@ namespace va {
|
||||
if (!display) {
|
||||
char string[1024];
|
||||
|
||||
auto bytes = readlink(("/proc/self/fd/" + std::to_string(fd)).c_str(), string, sizeof(string));
|
||||
auto bytes = readlink(std::format("/proc/self/fd/{}", fd).c_str(), string, sizeof(string));
|
||||
|
||||
std::string_view render_device {string, (std::size_t) bytes};
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
*/
|
||||
#define INITGUID
|
||||
|
||||
// standard includes
|
||||
#include <format>
|
||||
|
||||
// platform includes
|
||||
#include <audioclient.h>
|
||||
#include <Audioclient.h>
|
||||
#include <avrt.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <newdev.h>
|
||||
@@ -168,28 +171,27 @@ namespace {
|
||||
waveformat.SubFormat == KSDATAFORMAT_SUBTYPE_PCM ? "S" :
|
||||
"UNKNOWN";
|
||||
|
||||
result += std::to_string(waveformat.Samples.wValidBitsPerSample) + " " +
|
||||
std::to_string(waveformat.Format.nSamplesPerSec) + " ";
|
||||
result += std::format("{} {} ", static_cast<int>(waveformat.Samples.wValidBitsPerSample), static_cast<int>(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::to_string(waveformat.Format.nChannels) + " channels (unrecognized)";
|
||||
result += std::format("{} channels (unrecognized)", static_cast<int>(waveformat.Format.nChannels));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -375,7 +377,7 @@ namespace platf::audio {
|
||||
*ppvInterface = (IMMNotificationClient *) this;
|
||||
return S_OK;
|
||||
} else {
|
||||
*ppvInterface = NULL;
|
||||
*ppvInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
@@ -677,7 +679,7 @@ namespace platf::audio {
|
||||
float *sample_buf_pos;
|
||||
int channels;
|
||||
|
||||
HANDLE mmcss_task_handle = NULL;
|
||||
HANDLE mmcss_task_handle = nullptr;
|
||||
};
|
||||
|
||||
class audio_control_t: public ::platf::audio_control_t {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -601,12 +601,12 @@ namespace platf::dxgi {
|
||||
LUID val;
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), flags, &token) &&
|
||||
!!LookupPrivilegeValue(NULL, SE_INC_BASE_PRIORITY_NAME, &val)) {
|
||||
!!LookupPrivilegeValue(nullptr, 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), NULL, NULL)) {
|
||||
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), nullptr, nullptr)) {
|
||||
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",
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
"DXGI_FORMAT_P208",
|
||||
"DXGI_FORMAT_V208",
|
||||
|
||||
@@ -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 = NULL;
|
||||
img->encoder_texture_handle = nullptr;
|
||||
}
|
||||
|
||||
// Initialize format-dependent fields
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = 0;
|
||||
gamepad.repeat_task = nullptr;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
gamepad.repeat_task = nullptr;
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
@@ -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(NULL, sunshine_path, _countof(sunshine_path));
|
||||
GetModuleFileNameW(nullptr, 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(NULL, attribute_count, 0, &size);
|
||||
InitializeProcThreadAttributeList(nullptr, attribute_count, 0, &size);
|
||||
|
||||
auto list = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (list == NULL) {
|
||||
return NULL;
|
||||
if (list == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!InitializeProcThreadAttributeList(list, attribute_count, 0, &size)) {
|
||||
HeapFree(GetProcessHeap(), 0, list);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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 == NULL) {
|
||||
if (startup_info.lpAttributeList == nullptr) {
|
||||
// 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 = NULL;
|
||||
startup_info.StartupInfo.hStdInput = nullptr;
|
||||
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), NULL, NULL);
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &startup_info.StartupInfo.hStdOutput, sizeof(startup_info.StartupInfo.hStdOutput), nullptr, nullptr);
|
||||
}
|
||||
|
||||
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), NULL, NULL);
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, job, sizeof(*job), nullptr, nullptr);
|
||||
}
|
||||
|
||||
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 `NULL` to restore original keys.
|
||||
* @param token The primary token identifying the user to use, or `nullptr` 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 = NULL;
|
||||
HKEY user_classes_root = nullptr;
|
||||
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 = NULL;
|
||||
HKEY user_key = nullptr;
|
||||
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 = NULL;
|
||||
user_key = nullptr;
|
||||
}
|
||||
});
|
||||
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, NULL);
|
||||
RegOverridePredefKey(HKEY_CLASSES_ROOT, nullptr);
|
||||
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 `NULL` if running as ourselves.
|
||||
* @param token The user token currently being impersonated or `nullptr` 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(NULL);
|
||||
override_per_user_predefined_keys(nullptr);
|
||||
}
|
||||
|
||||
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, 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);
|
||||
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);
|
||||
});
|
||||
}
|
||||
// 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, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
HMODULE wlanapi = LoadLibraryExA("wlanapi.dll", nullptr, 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 = NULL;
|
||||
wlan_handle = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1200,7 +1200,7 @@ namespace platf {
|
||||
startup_info.StartupInfo.cb = sizeof(startup_info);
|
||||
|
||||
WCHAR executable[MAX_PATH];
|
||||
if (GetModuleFileNameW(NULL, executable, ARRAYSIZE(executable)) == 0) {
|
||||
if (GetModuleFileNameW(nullptr, 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() != NULL) {
|
||||
if (GetConsoleWindow() != nullptr) {
|
||||
// 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) NULL, flow_id, 0)) {
|
||||
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) nullptr, 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", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
HMODULE qwave = LoadLibraryExA("qwave.dll", nullptr, 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 != NULL;
|
||||
return timer != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE timer = NULL;
|
||||
HANDLE timer = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <string_view>
|
||||
|
||||
// platform includes
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
#include <winnt.h>
|
||||
|
||||
namespace platf {
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace nvprefs {
|
||||
void driver_settings_t::destroy() {
|
||||
if (session_handle) {
|
||||
NvAPI_DRS_DestroySession(session_handle);
|
||||
session_handle = 0;
|
||||
session_handle = nullptr;
|
||||
}
|
||||
NvAPI_Unload();
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace nvprefs {
|
||||
if (swapchain_data) {
|
||||
NvAPI_Status status;
|
||||
|
||||
NvDRSProfileHandle profile_handle = 0;
|
||||
NvDRSProfileHandle profile_handle = nullptr;
|
||||
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 = 0;
|
||||
NvDRSProfileHandle profile_handle = nullptr;
|
||||
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 = 0;
|
||||
NvDRSProfileHandle profile_handle = nullptr;
|
||||
status = NvAPI_DRS_FindProfileByName(session_handle, profile_name, &profile_handle);
|
||||
|
||||
if (status != NVAPI_OK) {
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace nvprefs {
|
||||
bool check_and_modify_application_profile(bool &modified);
|
||||
|
||||
private:
|
||||
NvDRSSessionHandle session_handle = 0;
|
||||
NvDRSSessionHandle session_handle = nullptr;
|
||||
};
|
||||
|
||||
} // namespace nvprefs
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
namespace {
|
||||
|
||||
std::map<const char *, void *> interfaces;
|
||||
HMODULE dll = NULL;
|
||||
HMODULE dll = nullptr;
|
||||
|
||||
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, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
|
||||
if ((dll = LoadLibraryEx(dll_name, nullptr, 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 = NULL;
|
||||
dll = nullptr;
|
||||
}
|
||||
return NVAPI_OK;
|
||||
}
|
||||
|
||||
@@ -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 != NULL && handle != INVALID_HANDLE_VALUE;
|
||||
return handle != nullptr && handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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, NULL));
|
||||
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_READ | DELETE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
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, NULL));
|
||||
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_WRITE | STANDARD_RIGHTS_ALL, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
if (file.file_handle) {
|
||||
// give GENERIC_READ, GENERIC_WRITE and DELETE permissions to Users group
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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";
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ extern "C" {
|
||||
// standard includes
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <format>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
@@ -864,7 +865,7 @@ namespace rtsp_stream {
|
||||
session_option.next = &port_option;
|
||||
|
||||
// Moonlight merely requires 'server_port=<port>'
|
||||
auto port_value = "server_port=" + std::to_string(port);
|
||||
auto port_value = std::format("server_port={}", static_cast<int>(port));
|
||||
|
||||
port_option.option = const_cast<char *>("Transport");
|
||||
port_option.content = port_value.data();
|
||||
|
||||
+18
-18
@@ -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() == NULL) {
|
||||
if (GetConsoleWindow() == nullptr) {
|
||||
lifetime::exit_sunshine(ERROR_SHUTDOWN_IN_PROGRESS, true);
|
||||
return;
|
||||
}
|
||||
@@ -230,10 +230,10 @@ namespace system_tray {
|
||||
return;
|
||||
}
|
||||
|
||||
tray.notification_title = NULL;
|
||||
tray.notification_text = NULL;
|
||||
tray.notification_cb = NULL;
|
||||
tray.notification_icon = NULL;
|
||||
tray.notification_title = nullptr;
|
||||
tray.notification_text = nullptr;
|
||||
tray.notification_cb = nullptr;
|
||||
tray.notification_icon = nullptr;
|
||||
tray.icon = TRAY_ICON_PLAYING;
|
||||
tray_update(&tray);
|
||||
tray.icon = TRAY_ICON_PLAYING;
|
||||
@@ -251,10 +251,10 @@ namespace system_tray {
|
||||
return;
|
||||
}
|
||||
|
||||
tray.notification_title = NULL;
|
||||
tray.notification_text = NULL;
|
||||
tray.notification_cb = NULL;
|
||||
tray.notification_icon = NULL;
|
||||
tray.notification_title = nullptr;
|
||||
tray.notification_text = nullptr;
|
||||
tray.notification_cb = nullptr;
|
||||
tray.notification_icon = nullptr;
|
||||
tray.icon = TRAY_ICON_PAUSING;
|
||||
tray_update(&tray);
|
||||
char msg[256];
|
||||
@@ -272,10 +272,10 @@ namespace system_tray {
|
||||
return;
|
||||
}
|
||||
|
||||
tray.notification_title = NULL;
|
||||
tray.notification_text = NULL;
|
||||
tray.notification_cb = NULL;
|
||||
tray.notification_icon = NULL;
|
||||
tray.notification_title = nullptr;
|
||||
tray.notification_text = nullptr;
|
||||
tray.notification_cb = nullptr;
|
||||
tray.notification_icon = nullptr;
|
||||
tray.icon = TRAY_ICON;
|
||||
tray_update(&tray);
|
||||
char msg[256];
|
||||
@@ -293,10 +293,10 @@ namespace system_tray {
|
||||
return;
|
||||
}
|
||||
|
||||
tray.notification_title = NULL;
|
||||
tray.notification_text = NULL;
|
||||
tray.notification_cb = NULL;
|
||||
tray.notification_icon = NULL;
|
||||
tray.notification_title = nullptr;
|
||||
tray.notification_text = nullptr;
|
||||
tray.notification_cb = nullptr;
|
||||
tray.notification_icon = nullptr;
|
||||
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_with_path("/pin");
|
||||
launch_ui("/pin");
|
||||
};
|
||||
tray_update(&tray);
|
||||
}
|
||||
|
||||
+5
-4
@@ -1890,9 +1890,10 @@ namespace video {
|
||||
}
|
||||
});
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||
auto packets = mail::man->queue<packet_t>(mail::video_packets);
|
||||
@@ -1943,7 +1944,7 @@ namespace video {
|
||||
|
||||
// Encode at a minimum FPS to avoid image quality issues with static content
|
||||
if (!requested_idr_frame || images->peek()) {
|
||||
if (auto img = images->pop(minimum_frame_time)) {
|
||||
if (auto img = images->pop(max_frametime)) {
|
||||
frame_timestamp = img->frame_timestamp;
|
||||
if (session->convert(*img)) {
|
||||
BOOST_LOG(error) << "Could not convert image"sv;
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
"dd_mode_remapping": {"mixed": [], "resolution_only": [], "refresh_rate_only": []},
|
||||
"dd_wa_hdr_toggle_delay": 0,
|
||||
"max_bitrate": 0,
|
||||
"minimum_fps_target": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -17,6 +17,13 @@ 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>
|
||||
|
||||
@@ -256,6 +256,8 @@
|
||||
"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",
|
||||
|
||||
@@ -27,7 +27,8 @@ 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
|
||||
for i in "${empty_dir}"; do # don't split words as we already know this will be a single directory
|
||||
# shellcheck disable=SC2066 # don't split words as we already know this will be a single directory
|
||||
for i in "${empty_dir}"; do
|
||||
echo "Removing empty directory: ${i}"
|
||||
rmdir "${i}"
|
||||
done
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
#include "../tests_common.h"
|
||||
|
||||
#include <format>
|
||||
#include <src/config.h>
|
||||
#include <src/display_device.h>
|
||||
#include <src/rtsp.h>
|
||||
@@ -473,7 +474,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::to_string(manual_res.m_width) + "x"s + std::to_string(manual_res.m_height);
|
||||
video_config.dd.manual_resolution = std::format("{}x{}", static_cast<int>(manual_res.m_width), static_cast<int>(manual_res.m_height));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
#include "../tests_common.h"
|
||||
|
||||
#include <format>
|
||||
#include <src/file_handler.h>
|
||||
|
||||
struct FileHandlerParentDirectoryTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
|
||||
@@ -79,13 +80,13 @@ Hey, hey, hey!
|
||||
|
||||
TEST_P(FileHandlerTests, WriteFileTest) {
|
||||
auto [fileNum, content] = GetParam();
|
||||
std::string fileName = "write_file_test_" + std::to_string(fileNum) + ".txt";
|
||||
const std::string fileName = std::format("write_file_test_{}.txt", fileNum);
|
||||
EXPECT_EQ(file_handler::write_file(fileName.c_str(), content), 0);
|
||||
}
|
||||
|
||||
TEST_P(FileHandlerTests, ReadFileTest) {
|
||||
auto [fileNum, content] = GetParam();
|
||||
std::string fileName = "write_file_test_" + std::to_string(fileNum) + ".txt";
|
||||
const std::string fileName = std::format("write_file_test_{}.txt", fileNum);
|
||||
EXPECT_EQ(file_handler::read_file(fileName.c_str()), content);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../tests_common.h"
|
||||
#include "../tests_log_checker.h"
|
||||
|
||||
#include <format>
|
||||
#include <random>
|
||||
#include <src/logging.h>
|
||||
|
||||
@@ -39,7 +40,7 @@ TEST_P(LogLevelsTest, PutMessage) {
|
||||
|
||||
std::random_device rand_dev;
|
||||
std::mt19937_64 rand_gen(rand_dev());
|
||||
auto test_message = std::to_string(rand_gen()) + std::to_string(rand_gen());
|
||||
auto test_message = std::format("{}{}", rand_gen(), rand_gen());
|
||||
BOOST_LOG(logger) << test_message;
|
||||
|
||||
ASSERT_TRUE(log_checker::line_contains(log_file, test_message));
|
||||
|
||||
Vendored
+1
-1
Submodule third-party/build-deps updated: a9a7f86328...94369e6377
+1
-1
@@ -5,7 +5,7 @@
|
||||
#define INITGUID
|
||||
|
||||
// platform includes
|
||||
#include <audioclient.h>
|
||||
#include <Audioclient.h>
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
|
||||
+34
-33
@@ -3,9 +3,10 @@
|
||||
* @brief Handles launching Sunshine.exe into user sessions as SYSTEM
|
||||
*/
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
#include <wtsapi32.h>
|
||||
#include <WtsApi32.h>
|
||||
|
||||
// PROC_THREAD_ATTRIBUTE_JOB_LIST is currently missing from MinGW headers
|
||||
#ifndef PROC_THREAD_ATTRIBUTE_JOB_LIST
|
||||
@@ -51,9 +52,9 @@ DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, L
|
||||
}
|
||||
|
||||
HANDLE CreateJobObjectForChildProcess() {
|
||||
HANDLE job_handle = CreateJobObjectW(NULL, NULL);
|
||||
HANDLE job_handle = CreateJobObjectW(nullptr, nullptr);
|
||||
if (!job_handle) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limit_info = {};
|
||||
@@ -68,7 +69,7 @@ HANDLE CreateJobObjectForChildProcess() {
|
||||
|
||||
if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_limit_info, sizeof(job_limit_info))) {
|
||||
CloseHandle(job_handle);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return job_handle;
|
||||
@@ -76,16 +77,16 @@ HANDLE CreateJobObjectForChildProcess() {
|
||||
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST AllocateProcThreadAttributeList(DWORD attribute_count) {
|
||||
SIZE_T size;
|
||||
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
|
||||
InitializeProcThreadAttributeList(nullptr, attribute_count, 0, &size);
|
||||
|
||||
auto list = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (list == NULL) {
|
||||
return NULL;
|
||||
if (list == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!InitializeProcThreadAttributeList(list, attribute_count, 0, &size)) {
|
||||
HeapFree(GetProcessHeap(), 0, list);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return list;
|
||||
@@ -94,14 +95,14 @@ LPPROC_THREAD_ATTRIBUTE_LIST AllocateProcThreadAttributeList(DWORD attribute_cou
|
||||
HANDLE DuplicateTokenForSession(DWORD console_session_id) {
|
||||
HANDLE current_token;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, ¤t_token)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Duplicate our own LocalSystem token
|
||||
HANDLE new_token;
|
||||
if (!DuplicateTokenEx(current_token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token)) {
|
||||
if (!DuplicateTokenEx(current_token, TOKEN_ALL_ACCESS, nullptr, SecurityImpersonation, TokenPrimary, &new_token)) {
|
||||
CloseHandle(current_token);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CloseHandle(current_token);
|
||||
@@ -109,7 +110,7 @@ HANDLE DuplicateTokenForSession(DWORD console_session_id) {
|
||||
// Change the duplicated token to the console session ID
|
||||
if (!SetTokenInformation(new_token, TokenSessionId, &console_session_id, sizeof(console_session_id))) {
|
||||
CloseHandle(new_token);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new_token;
|
||||
@@ -123,21 +124,21 @@ HANDLE OpenLogFileHandle() {
|
||||
wcscat_s(log_file_name, L"sunshine.log");
|
||||
|
||||
// The file handle must be inheritable for our child process to use it
|
||||
SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), NULL, TRUE};
|
||||
SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), nullptr, TRUE};
|
||||
|
||||
// Overwrite the old sunshine.log
|
||||
return CreateFileW(log_file_name, GENERIC_WRITE, FILE_SHARE_READ, &security_attributes, CREATE_ALWAYS, 0, NULL);
|
||||
return CreateFileW(log_file_name, GENERIC_WRITE, FILE_SHARE_READ, &security_attributes, CREATE_ALWAYS, 0, nullptr);
|
||||
}
|
||||
|
||||
bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
|
||||
WCHAR module_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, module_path, _countof(module_path));
|
||||
GetModuleFileNameW(nullptr, module_path, _countof(module_path));
|
||||
std::wstring command;
|
||||
|
||||
command += L'"';
|
||||
command += module_path;
|
||||
command += L'"';
|
||||
command += L" --terminate " + std::to_wstring(pid);
|
||||
command += std::format(L" --terminate {}", pid);
|
||||
|
||||
STARTUPINFOW startup_info = {};
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
@@ -146,7 +147,7 @@ bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
|
||||
// Execute ourselves as a detached process in the user session with the --terminate argument.
|
||||
// This will allow us to attach to Sunshine's console and send it a Ctrl-C event.
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (!CreateProcessAsUserW(console_token, module_path, (LPWSTR) command.c_str(), NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS, NULL, NULL, &startup_info, &process_info)) {
|
||||
if (!CreateProcessAsUserW(console_token, module_path, (LPWSTR) command.c_str(), nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS, nullptr, nullptr, &startup_info, &process_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,8 +167,8 @@ bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
|
||||
}
|
||||
|
||||
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
service_status_handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, HandlerEx, NULL);
|
||||
if (service_status_handle == NULL) {
|
||||
service_status_handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, HandlerEx, nullptr);
|
||||
if (service_status_handle == nullptr) {
|
||||
// Nothing we can really do here but terminate ourselves
|
||||
ExitProcess(GetLastError());
|
||||
return;
|
||||
@@ -184,8 +185,8 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
SetServiceStatus(service_status_handle, &service_status);
|
||||
|
||||
// Create a manual-reset stop event
|
||||
stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
if (stop_event == NULL) {
|
||||
stop_event = CreateEventA(nullptr, TRUE, FALSE, nullptr);
|
||||
if (stop_event == nullptr) {
|
||||
// Tell SCM we failed to start
|
||||
service_status.dwWin32ExitCode = GetLastError();
|
||||
service_status.dwCurrentState = SERVICE_STOPPED;
|
||||
@@ -194,8 +195,8 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
}
|
||||
|
||||
// Create an auto-reset session change event
|
||||
session_change_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
if (session_change_event == NULL) {
|
||||
session_change_event = CreateEventA(nullptr, FALSE, FALSE, nullptr);
|
||||
if (session_change_event == nullptr) {
|
||||
// Tell SCM we failed to start
|
||||
service_status.dwWin32ExitCode = GetLastError();
|
||||
service_status.dwCurrentState = SERVICE_STOPPED;
|
||||
@@ -217,13 +218,13 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
startup_info.StartupInfo.cb = sizeof(startup_info);
|
||||
startup_info.StartupInfo.lpDesktop = (LPWSTR) L"winsta0\\default";
|
||||
startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
startup_info.StartupInfo.hStdInput = NULL;
|
||||
startup_info.StartupInfo.hStdInput = nullptr;
|
||||
startup_info.StartupInfo.hStdOutput = log_file_handle;
|
||||
startup_info.StartupInfo.hStdError = log_file_handle;
|
||||
|
||||
// Allocate an attribute list with space for 2 entries
|
||||
startup_info.lpAttributeList = AllocateProcThreadAttributeList(2);
|
||||
if (startup_info.lpAttributeList == NULL) {
|
||||
if (startup_info.lpAttributeList == nullptr) {
|
||||
// Tell SCM we failed to start
|
||||
service_status.dwWin32ExitCode = GetLastError();
|
||||
service_status.dwCurrentState = SERVICE_STOPPED;
|
||||
@@ -232,7 +233,7 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
}
|
||||
|
||||
// Only allow Sunshine.exe to inherit the log file handle, not all inheritable handles
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &log_file_handle, sizeof(log_file_handle), NULL, NULL);
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &log_file_handle, sizeof(log_file_handle), nullptr, nullptr);
|
||||
|
||||
// Tell SCM we're running (and stoppable now)
|
||||
service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN | SERVICE_ACCEPT_SESSIONCHANGE;
|
||||
@@ -248,22 +249,22 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
}
|
||||
|
||||
auto console_token = DuplicateTokenForSession(console_session_id);
|
||||
if (console_token == NULL) {
|
||||
if (console_token == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Job objects cannot span sessions, so we must create one for each process
|
||||
auto job_handle = CreateJobObjectForChildProcess();
|
||||
if (job_handle == NULL) {
|
||||
if (job_handle == nullptr) {
|
||||
CloseHandle(console_token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start Sunshine.exe inside our job object
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &job_handle, sizeof(job_handle), NULL, NULL);
|
||||
UpdateProcThreadAttribute(startup_info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &job_handle, sizeof(job_handle), nullptr, nullptr);
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (!CreateProcessAsUserW(console_token, L"Sunshine.exe", NULL, NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, (LPSTARTUPINFOW) &startup_info, &process_info)) {
|
||||
if (!CreateProcessAsUserW(console_token, L"Sunshine.exe", nullptr, nullptr, nullptr, TRUE, CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr, (LPSTARTUPINFOW) &startup_info, &process_info)) {
|
||||
CloseHandle(console_token);
|
||||
CloseHandle(job_handle);
|
||||
continue;
|
||||
@@ -326,7 +327,7 @@ int DoGracefulTermination(DWORD pid) {
|
||||
}
|
||||
|
||||
// Disable our own Ctrl-C handling
|
||||
SetConsoleCtrlHandler(NULL, TRUE);
|
||||
SetConsoleCtrlHandler(nullptr, TRUE);
|
||||
|
||||
// Send a Ctrl-C event to Sunshine
|
||||
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
|
||||
@@ -339,7 +340,7 @@ int DoGracefulTermination(DWORD pid) {
|
||||
int main(int argc, char *argv[]) {
|
||||
static const SERVICE_TABLE_ENTRY service_table[] = {
|
||||
{(LPSTR) SERVICE_NAME, ServiceMain},
|
||||
{NULL, NULL}
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
// Check if this is a reinvocation of ourselves to send Ctrl-C to Sunshine.exe
|
||||
@@ -351,7 +352,7 @@ int main(int argc, char *argv[]) {
|
||||
// We want to use the directory where Sunshine.exe is located instead of system32.
|
||||
// This requires stripping off 2 path components: the file name and the last folder
|
||||
WCHAR module_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, module_path, _countof(module_path));
|
||||
GetModuleFileNameW(nullptr, module_path, _countof(module_path));
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
auto last_sep = wcsrchr(module_path, '\\');
|
||||
if (last_sep) {
|
||||
|
||||
Reference in New Issue
Block a user