diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8c9df6e33bb..88c8339c68f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,7 +29,7 @@ updates: target-branch: "nightly" open-pull-requests-limit: 10 - - package-ecosystem: "pip" + - package-ecosystem: "nuget" directory: "/" schedule: interval: "daily" @@ -37,10 +37,18 @@ updates: target-branch: "nightly" open-pull-requests-limit: 10 - - package-ecosystem: "gitsubmodule" + - package-ecosystem: "pip" directory: "/" schedule: interval: "daily" time: "10:00" target-branch: "nightly" open-pull-requests-limit: 10 + + - package-ecosystem: "gitsubmodule" + directory: "/" + schedule: + interval: "daily" + time: "10:30" + target-branch: "nightly" + open-pull-requests-limit: 10 diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 09d15d48a31..211eaed4785 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -946,7 +946,7 @@ jobs: runs-on: windows-latest # the required action can only be run on Windows steps: - name: Release to WinGet - uses: vedantmgoyal2009/winget-releaser@v1 + uses: vedantmgoyal2009/winget-releaser@v2 with: identifier: LizardByte.Sunshine release-tag: ${{ needs.setup_release.outputs.release_tag }} diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 48f9c8cb343..3858ae100ac 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -315,7 +315,7 @@ jobs: - name: Build artifacts if: ${{ steps.prepare.outputs.artifacts == 'true' }} id: build_artifacts - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: ./ file: ${{ matrix.dockerfile }} @@ -334,7 +334,7 @@ jobs: - name: Build and push id: build - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: ./ file: ${{ matrix.dockerfile }} @@ -362,7 +362,7 @@ jobs: if: ${{ steps.prepare.outputs.artifacts == 'true' }} uses: actions/upload-artifact@v3 with: - name: sunshine${{ matrix.tag }} + name: Docker${{ matrix.tag }} path: artifacts/ - name: Create/Update GitHub Release diff --git a/CHANGELOG.md b/CHANGELOG.md index ace5c51d0d3..e778b7a0152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.18.2] - 2023-02-13 +### Fixed +- (Video/KMV/Linux) Fixed wayland capture on Nvidia for KMS +- (Video/Linux) Implement vaSyncBuffer stuf for libva <2.9.0 +- (UI) Fix issue where mime type was not being set for node_modules when using a reverse proxy +- (UI/macOS) Added missing audio sink config options +- (Linux) Specify correct Boost dependency versions +- (Video/AMF) Add missing encoder tunables + ## [0.18.1] - 2023-01-31 ### Fixed - (Linux) Fixed missing dependencies for deb and rpm packages @@ -307,3 +316,4 @@ settings. In v0.17.0, games now run under your user account without elevated pri [0.17.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.17.0 [0.18.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.18.0 [0.18.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.18.1 +[0.18.2]: https://github.com/LizardByte/Sunshine/releases/tag/v0.18.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1842c6743a3..93cccb7f9cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.18) # `CMAKE_CUDA_ARCHITECTURES` requires 3.18 -project(Sunshine VERSION 0.18.1 +project(Sunshine VERSION 0.18.2 DESCRIPTION "Sunshine is a self-hosted game stream host for Moonlight." HOMEPAGE_URL "https://app.lizardbyte.dev") @@ -789,10 +789,10 @@ elseif(UNIX) set(CPACK_DEB_COMPONENT_INSTALL ON) set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ ${CPACK_DEB_PLATFORM_PACKAGE_DEPENDS} \ - libboost-filesystem1.67.0 | libboost-filesystem1.71.0 | libboost-filesystem1.74.0, \ - libboost-log1.67.0 | libboost-log1.71.0 | libboost-log1.74.0, \ - libboost-program-options1.67.0 | libboost-program-options1.71.0 | libboost-program-options1.74.0, \ - libboost-thread1.67.0 | libboost-thread1.71.0 | libboost-thread1.74.0, \ + libboost-filesystem${Boost_VERSION}, \ + libboost-log${Boost_VERSION}, \ + libboost-program-options${Boost_VERSION}, \ + libboost-thread${Boost_VERSION}, \ libcap2, \ libcurl4, \ libdrm2, \ @@ -808,10 +808,10 @@ elseif(UNIX) openssl | libssl3") set(CPACK_RPM_PACKAGE_REQUIRES "\ ${CPACK_RPM_PLATFORM_PACKAGE_REQUIRES} \ - boost-filesystem >= 1.67.0, \ - boost-log >= 1.67.0, \ - boost-program-options >= 1.67.0, \ - boost-thread >= 1.67.0, \ + boost-filesystem >= ${Boost_VERSION}, \ + boost-log >= ${Boost_VERSION}, \ + boost-program-options >= ${Boost_VERSION}, \ + boost-thread >= ${Boost_VERSION}, \ libcap >= 2.22, \ libcurl >= 7.0, \ libdrm >= 2.4.97, \ diff --git a/docs/requirements.txt b/docs/requirements.txt index 24cbabce74b..9c21c08ffea 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ furo==2022.12.7 -m2r2==0.3.3 +m2r2==0.3.3.post2 Sphinx==6.1.3 sphinx-copybutton==0.5.1 diff --git a/docs/source/about/advanced_usage.rst b/docs/source/about/advanced_usage.rst index ee1776c6790..1e46bb57104 100644 --- a/docs/source/about/advanced_usage.rst +++ b/docs/source/about/advanced_usage.rst @@ -1081,6 +1081,68 @@ amd_rc amd_rc = vbr_latency +amd_usage +^^^^^^^^^ + +**Description** + The encoder usage profile, used to balance latency with encoding quality. + + .. Note:: This option only applies when using amdvce `encoder`_. + +**Choices** + +.. table:: + :widths: auto + + =============== =========== + Value Description + =============== =========== + transcoding transcoding (slowest) + webcam webcam (slow) + lowlatency low latency (fast) + ultralowlatency ultra low latency (fastest) + =============== =========== + +**Default** + ``ultralowlatency`` + +**Example** + .. code-block:: text + + amd_usage = ultralowlatency + +amd_preanalysis +^^^^^^^^^^^^^^^ + +**Description** + Preanalysis can increase encoding quality at the cost of latency. + + .. Note:: This option only applies when using amdvce `encoder`_. + +**Default** + ``disabled`` + +**Example** + .. code-block:: text + + amd_preanalysis = disabled + +amd_vbaq +^^^^^^^^ + +**Description** + Variance Based Adaptive Quantization (VBAQ) can increase subjective visual quality. + + .. Note:: This option only applies when using amdvce `encoder`_. + +**Default** + ``enabled`` + +**Example** + .. code-block:: text + + amd_vbaq = enabled + amd_coder ^^^^^^^^^ diff --git a/docs/source/about/usage.rst b/docs/source/about/usage.rst index 7861e52321d..6422a72e5e2 100644 --- a/docs/source/about/usage.rst +++ b/docs/source/about/usage.rst @@ -146,8 +146,7 @@ macOS ^^^^^ Sunshine can only access microphones on macOS due to system limitations. To stream system audio use `Soundflower `_ or -`BlackHole `_ and -select their sink as audio device in `sunshine.conf`. +`BlackHole `_. .. Note:: Command Keys are not forwarded by Moonlight. Right Option-Key is mapped to CMD-Key. diff --git a/src/config.cpp b/src/config.cpp index 11c393a8cbc..7e93ee6298e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -130,6 +130,14 @@ namespace amd { #define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR 1 #define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR 2 #define AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR 3 +#define AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING 0 +#define AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY 1 +#define AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY 2 +#define AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM 3 +#define AMF_VIDEO_ENCODER_USAGE_TRANSCONDING 0 +#define AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY 1 +#define AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY 2 +#define AMF_VIDEO_ENCODER_USAGE_WEBCAM 3 #define AMF_VIDEO_ENCODER_UNDEFINED 0 #define AMF_VIDEO_ENCODER_CABAC 1 #define AMF_VIDEO_ENCODER_CALV 2 @@ -164,6 +172,20 @@ enum class rc_h264_e : int { cbr = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }; +enum class usage_hevc_e : int { + transcoding = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING, + webcam = AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM, + lowlatency = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY, + ultralowlatency = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY +}; + +enum class usage_h264_e : int { + transcoding = AMF_VIDEO_ENCODER_USAGE_TRANSCONDING, + webcam = AMF_VIDEO_ENCODER_USAGE_WEBCAM, + lowlatency = AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY, + ultralowlatency = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY +}; + enum coder_e : int { _auto = AMF_VIDEO_ENCODER_UNDEFINED, cabac = AMF_VIDEO_ENCODER_CABAC, @@ -191,6 +213,17 @@ std::optional rc_from_view(const std::string_view &rc, int codec) { return std::nullopt; } +std::optional usage_from_view(const std::string_view &rc, int codec) { +#define _CONVERT_(x) \ + if(rc == #x##sv) return codec == 0 ? (int)usage_hevc_e::x : (int)usage_h264_e::x + _CONVERT_(transcoding); + _CONVERT_(webcam); + _CONVERT_(lowlatency); + _CONVERT_(ultralowlatency); +#undef _CONVERT_ + return std::nullopt; +} + int coder_from_view(const std::string_view &coder) { if(coder == "auto"sv) return _auto; if(coder == "cabac"sv || coder == "ac"sv) return cabac; @@ -300,12 +333,16 @@ video_t video { }, // qsv { - (int)amd::quality_h264_e::balanced, // quality (h264) - (int)amd::quality_hevc_e::balanced, // quality (hevc) - (int)amd::rc_h264_e::vbr_latency, // rate control (h264) - (int)amd::rc_hevc_e::vbr_latency, // rate control (hevc) - (int)amd::coder_e::_auto, // coder - }, // amd + (int)amd::quality_h264_e::balanced, // quality (h264) + (int)amd::quality_hevc_e::balanced, // quality (hevc) + (int)amd::rc_h264_e::vbr_latency, // rate control (h264) + (int)amd::rc_hevc_e::vbr_latency, // rate control (hevc) + (int)amd::usage_h264_e::ultralowlatency, // usage (h264) + (int)amd::usage_hevc_e::ultralowlatency, // usage (hevc) + 0, // preanalysis + 1, // vbaq + (int)amd::coder_e::_auto, // coder + }, // amd { 0, @@ -826,6 +863,16 @@ void apply_config(std::unordered_map &&vars) { video.amd.rc_hevc = amd::rc_from_view(rc, 0); } + std::string usage; + string_f(vars, "amd_usage", usage); + if(!usage.empty()) { + video.amd.usage_h264 = amd::usage_from_view(rc, 1); + video.amd.usage_hevc = amd::usage_from_view(rc, 0); + } + + bool_f(vars, "amd_preanalysis", (bool &)video.amd.preanalysis); + bool_f(vars, "amd_vbaq", (bool &)video.amd.vbaq); + int_f(vars, "vt_coder", video.vt.coder, vt::coder_from_view); int_f(vars, "vt_software", video.vt.allow_sw, vt::allow_software_from_view); int_f(vars, "vt_software", video.vt.require_sw, vt::force_software_from_view); diff --git a/src/config.h b/src/config.h index a95e0f854ae..77bf9506983 100644 --- a/src/config.h +++ b/src/config.h @@ -38,6 +38,10 @@ struct video_t { std::optional quality_hevc; std::optional rc_h264; std::optional rc_hevc; + std::optional usage_h264; + std::optional usage_hevc; + std::optional preanalysis; + std::optional vbaq; int coder; } amd; diff --git a/src/confighttp.cpp b/src/confighttp.cpp index e86ca9c1867..7425e7f5646 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -144,6 +144,7 @@ void not_found(resp_https_t response, req_https_t request) { << data.str(); } +// todo - combine these functions into a single function that accepts the page, i.e "index", "pin", "apps" void getIndexPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; @@ -229,6 +230,8 @@ void getTroubleshootingPage(resp_https_t response, req_https_t request) { } void getFaviconImage(resp_https_t response, req_https_t request) { + // todo - combine function with getSunshineLogoImage and possibly getNodeModules + // todo - use mime_types map print_req(request); std::ifstream in(WEB_DIR "images/favicon.ico", std::ios::binary); @@ -238,6 +241,8 @@ void getFaviconImage(resp_https_t response, req_https_t request) { } void getSunshineLogoImage(resp_https_t response, req_https_t request) { + // todo - combine function with getFaviconImage and possibly getNodeModules + // todo - use mime_types map print_req(request); std::ifstream in(WEB_DIR "images/logo-sunshine-45.png", std::ios::binary); @@ -269,17 +274,18 @@ void getNodeModules(resp_https_t response, req_https_t request) { } else { auto relPath = fs::relative(filePath, webDirPath); - if(relPath.extension() == ".ttf" or relPath.extension() == ".woff2") { - // Fonts are read differntly + // get the mime type from the file extension mime_types map + // remove the leading period from the extension + auto mimeType = mime_types.find(relPath.extension().string().substr(1)); + // check if the extension is in the map at the x position + if(mimeType != mime_types.end()) { + // if it is, set the content type to the mime type SimpleWeb::CaseInsensitiveMultimap headers; - std::ifstream in((filePath).c_str(), std::ios::binary); - headers.emplace("Content-Type", "font/" + filePath.extension().string().substr(1)); + headers.emplace("Content-Type", mimeType->second); + std::ifstream in(filePath.string(), std::ios::binary); response->write(SimpleWeb::StatusCode::success_ok, in, headers); } - else { - std::string content = read_file((filePath.string()).c_str()); - response->write(content); - } + // do not return any file if the type is not in the map } } diff --git a/src/confighttp.h b/src/confighttp.h index cae32aefdb5..b178ff1d455 100644 --- a/src/confighttp.h +++ b/src/confighttp.h @@ -16,4 +16,23 @@ constexpr auto PORT_HTTPS = 1; void start(); } // namespace confighttp +// mime types map +const std::map mime_types = { + { "css", "text/css" }, + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "ico", "image/x-icon" }, + { "jpeg", "image/jpeg" }, + { "jpg", "image/jpeg" }, + { "js", "application/javascript" }, + { "json", "application/json" }, + { "png", "image/png" }, + { "svg", "image/svg+xml" }, + { "ttf", "font/ttf" }, + { "txt", "text/plain" }, + { "woff2", "font/woff2" }, + { "xml", "text/xml" }, +}; + #endif // SUNSHINE_CONFIGHTTP_H diff --git a/src/platform/linux/kmsgrab.cpp b/src/platform/linux/kmsgrab.cpp index 240ce696859..6ca7220c9eb 100644 --- a/src/platform/linux/kmsgrab.cpp +++ b/src/platform/linux/kmsgrab.cpp @@ -755,6 +755,12 @@ class display_ram_t : public display_t { auto &rgb = *rgb_opt; gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]); + + int w, h; + gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + BOOST_LOG(debug) << "width and height: w "sv << w << " h "sv << h; + gl::ctx.GetTextureSubImage(rgb->tex[0], 0, img_offset_x, img_offset_y, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out_base->height * img_out_base->row_pitch, img_out_base->data); if(cursor_opt && cursor) { diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index 8f97db271e2..1054d9fccdf 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -5,6 +5,17 @@ extern "C" { #include +#include +#if !VA_CHECK_VERSION(1, 9, 0) +/* vaSyncBuffer stub allows Sunshine built against libva <2.9.0 + to link against ffmpeg on libva 2.9.0 or later */ +VAStatus vaSyncBuffer( + VADisplay dpy, + VABufferID buf_id, + uint64_t timeout_ns) { + return VA_STATUS_ERROR_UNIMPLEMENTED; +} +#endif } #include "graphics.h" diff --git a/src/platform/linux/wlgrab.cpp b/src/platform/linux/wlgrab.cpp index ea4adc8d997..00a34c28c85 100644 --- a/src/platform/linux/wlgrab.cpp +++ b/src/platform/linux/wlgrab.cpp @@ -167,7 +167,7 @@ class wlr_ram_t : public wlr_t { int w, h; gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); - gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &h); + gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); BOOST_LOG(debug) << "width and height: w "sv << w << " h "sv << h; gl::ctx.GetTextureSubImage((*rgb_opt)->tex[0], 0, 0, 0, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out_base->height * img_out_base->row_pitch, img_out_base->data); diff --git a/src/video.cpp b/src/video.cpp index 9389ee3d7dc..4a7ac86487f 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -539,15 +539,16 @@ static encoder_t amdvce { { // Common options { - { "enforce_hrd"s, true }, + { "filler_data"s, true }, { "gops_per_idr"s, 1 }, { "header_insertion_mode"s, "idr"s }, + { "preanalysis"s, &config::video.amd.preanalysis }, { "qmax"s, 51 }, { "qmin"s, 0 }, { "quality"s, &config::video.amd.quality_hevc }, { "rc"s, &config::video.amd.rc_hevc }, - { "usage"s, "ultralowlatency"s }, - { "vbaq"s, true }, + { "usage"s, &config::video.amd.usage_hevc }, + { "vbaq"s, &config::video.amd.vbaq }, }, {}, // SDR-specific options {}, // HDR-specific options @@ -557,14 +558,15 @@ static encoder_t amdvce { { // Common options { - { "enforce_hrd"s, true }, + { "filler_data"s, true }, { "log_to_dbg"s, "1"s }, + { "preanalysis"s, &config::video.amd.preanalysis }, { "qmax"s, 51 }, { "qmin"s, 0 }, { "quality"s, &config::video.amd.quality_h264 }, { "rc"s, &config::video.amd.rc_h264 }, - { "usage"s, "ultralowlatency"s }, - { "vbaq"s, true }, + { "usage"s, &config::video.amd.usage_h264 }, + { "vbaq"s, &config::video.amd.vbaq }, }, {}, // SDR-specific options {}, // HDR-specific options diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index 1bc06507e4d..9fbc08547ba 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -369,6 +369,29 @@

Configuration


+
+ + +
+ The name of the audio sink used for Audio Loopback
+ Sunshine can only access microphones on macOS due to system limitations.
+ To stream system audio using + Soundflower + or + BlackHole + . +
+
@@ -742,6 +765,29 @@

Configuration

+
+ + +
+
+ + +
+
+ + +