From 3092471be5a36e2db2174bd7137b90e082571b0b Mon Sep 17 00:00:00 2001 From: Andy Grundman Date: Wed, 21 May 2025 19:56:41 -0400 Subject: [PATCH 1/8] fix(rtp): improve timestamp accuracy for video (#3883) Instead of using now() when the RTP packet is created, use the earlier packet->frame_timestamp that we're already collecting for host latency stats. This timestamp is more accurate to when we captured the frame, and the same timestamp value is shared by all RTP packets that make up the same video frame. Duplicate frames without capture timestamps use the ratecontrol timestamp. --- src/stream.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/stream.cpp b/src/stream.cpp index 2572d555..e6bb5ebf 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1263,7 +1263,7 @@ namespace stream { void videoBroadcastThread(udp::socket &sock) { auto shutdown_event = mail::man->event(mail::broadcast_shutdown); auto packets = mail::man->queue(mail::video_packets); - auto timebase = boost::posix_time::microsec_clock::universal_time(); + auto video_epoch = std::chrono::steady_clock::now(); // Video traffic is sent on this thread platf::adjust_thread_priority(platf::thread_priority_e::high); @@ -1459,14 +1459,20 @@ namespace stream { size_t next_shard_to_send = 0; + // RTP video timestamps use a 90 KHz clock and the frame_timestamp from when the frame was captured + // When a timestamp isn't available (duplicate frames), the timestamp from rate control is used instead. + bool frame_is_dupe = false; + if (!packet->frame_timestamp) { + packet->frame_timestamp = ratecontrol_next_frame_start; + frame_is_dupe = true; + } + using rtp_tick = std::chrono::duration>; + uint32_t timestamp = std::chrono::round(*packet->frame_timestamp - video_epoch).count(); + // set FEC info now that we know for sure what our percentage will be for this frame for (auto x = 0; x < shards.size(); ++x) { auto *inspect = (video_packet_raw_t *) shards.data(x); - // RTP video timestamps use a 90 KHz clock - auto now = boost::posix_time::microsec_clock::universal_time(); - auto timestamp = (now - timebase).total_microseconds() / (1000 / 90); - inspect->packet.fecInfo = (x << 12 | shards.data_shards << 22 | @@ -1558,11 +1564,11 @@ namespace stream { frame_network_latency_logger.second_point_now_and_log(); - if (packet->is_idr()) { - BOOST_LOG(verbose) << "Key Frame ["sv << packet->frame_index() << "] :: send ["sv << shards.size() << "] shards..."sv; - } else { - BOOST_LOG(verbose) << "Frame ["sv << packet->frame_index() << "] :: send ["sv << shards.size() << "] shards..."sv << std::endl; - } + BOOST_LOG(verbose) << "Sent Frame seq ["sv << packet->frame_index() << "] pts ["sv << timestamp + << "] shards ["sv << shards.size() << "/"sv << shards.percentage << "%]"sv + << (frame_is_dupe ? " Dupe" : "") + << (packet->is_idr() ? " Key" : "") + << (packet->after_ref_frame_invalidation ? " RFI" : ""); ++blockIndex; lowseq += shards.size(); @@ -1622,6 +1628,8 @@ namespace stream { break; } + BOOST_LOG(verbose) << "Audio [seq "sv << sequenceNumber << ", pts "sv << timestamp << "] :: send..."sv; + audio_packet.rtp.sequenceNumber = util::endian::big(sequenceNumber); audio_packet.rtp.timestamp = util::endian::big(timestamp); @@ -1641,7 +1649,6 @@ namespace stream { session->localAddress, }; platf::send(send_info); - BOOST_LOG(verbose) << "Audio ["sv << sequenceNumber << "] :: send..."sv; auto &fec_packet = session->audio.fec_packet; // initialize the FEC header at the beginning of the FEC block From 9effeba5fe4e025765a71048a74d4749a052b0fa Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 23 May 2025 22:16:24 -0400 Subject: [PATCH 2/8] ci(homebrew): fix python for macOS-13 (#3899) --- .github/workflows/CI.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 33d0f2c8..6c04ccba 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -524,6 +524,8 @@ jobs: rm '/usr/local/bin/idle3' rm '/usr/local/bin/idle3.12' rm '/usr/local/bin/idle3.13' + rm '/usr/local/bin/pip3.12' + rm '/usr/local/bin/pip3.13' rm '/usr/local/bin/pydoc3' rm '/usr/local/bin/pydoc3.12' rm '/usr/local/bin/pydoc3.13' @@ -533,13 +535,7 @@ jobs: rm '/usr/local/bin/python3-config' rm '/usr/local/bin/python3.12-config' rm '/usr/local/bin/python3.13-config' - brew install python - - - name: Setup python - id: python - uses: actions/setup-python@v5 - with: - python-version: '3.11' + brew install python3 - name: Configure formula run: | @@ -630,6 +626,12 @@ jobs: token: ${{ secrets.GH_BOT_TOKEN }} validate: true + - name: Setup python + id: python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Generate gcov report id: test_report # any except canceled or skipped From 5e049e3c619f556da902320cbc3226f0ebc85010 Mon Sep 17 00:00:00 2001 From: Clutchnp <105556048+Clutchnp@users.noreply.github.com> Date: Sat, 24 May 2025 09:19:09 +0530 Subject: [PATCH 3/8] build(cmake): export compile commands (#3894) --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea145ced..5cedee55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,9 @@ endif() # set the module path, used for includes set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +# export compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # set version info for this build include(${CMAKE_MODULE_PATH}/prep/build_version.cmake) From ae1ee8fb45dbf2c3a25200e4b9eca1225ab27dd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 May 2025 13:41:55 +0000 Subject: [PATCH 4/8] build(deps): bump the lizardbyte-actions group with 2 updates (#3822) Bumps the lizardbyte-actions group with 2 updates: [LizardByte/homebrew-release-action](https://github.com/lizardbyte/homebrew-release-action) and [LizardByte/update-changelog-action](https://github.com/lizardbyte/update-changelog-action). Updates `LizardByte/homebrew-release-action` from 2024.1115.14934 to 2025.426.194543 - [Release notes](https://github.com/lizardbyte/homebrew-release-action/releases) - [Commits](https://github.com/lizardbyte/homebrew-release-action/compare/v2024.1115.14934...v2025.426.194543) Updates `LizardByte/update-changelog-action` from 2024.919.152649 to 2025.426.173858 - [Release notes](https://github.com/lizardbyte/update-changelog-action/releases) - [Commits](https://github.com/lizardbyte/update-changelog-action/compare/v2024.919.152649...v2025.426.173858) --- updated-dependencies: - dependency-name: LizardByte/homebrew-release-action dependency-version: 2025.426.194543 dependency-type: direct:production update-type: version-update:semver-major dependency-group: lizardbyte-actions - dependency-name: LizardByte/update-changelog-action dependency-version: 2025.426.173858 dependency-type: direct:production update-type: version-update:semver-major dependency-group: lizardbyte-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 4 ++-- .github/workflows/update-changelog.yml | 2 +- .github/workflows/update-homebrew-release.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6c04ccba..e1171a27 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -617,7 +617,7 @@ jobs: - name: Validate Homebrew Formula id: test if: matrix.release != true - uses: LizardByte/homebrew-release-action@v2025.503.165455 + uses: LizardByte/homebrew-release-action@v2025.506.15440 with: formula_file: ${{ github.workspace }}/homebrew/sunshine.rb git_email: ${{ secrets.GH_BOT_EMAIL }} @@ -730,7 +730,7 @@ jobs: github.repository_owner == 'LizardByte' && matrix.release && needs.setup_release.outputs.publish_release == 'true' - uses: LizardByte/homebrew-release-action@v2025.503.165455 + uses: LizardByte/homebrew-release-action@v2025.506.15440 with: formula_file: ${{ github.workspace }}/homebrew/sunshine-beta.rb git_email: ${{ secrets.GH_BOT_EMAIL }} diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 394a2432..35ed0b93 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Update Changelog - uses: LizardByte/update-changelog-action@v2024.919.152649 + uses: LizardByte/update-changelog-action@v2025.426.173858 with: changelogBranch: changelog changelogFile: CHANGELOG.md diff --git a/.github/workflows/update-homebrew-release.yml b/.github/workflows/update-homebrew-release.yml index cc442e8d..10e03d59 100644 --- a/.github/workflows/update-homebrew-release.yml +++ b/.github/workflows/update-homebrew-release.yml @@ -63,7 +63,7 @@ jobs: if: >- steps.check-label.outputs.hasTopic == 'true' && fromJson(steps.download.outputs.downloaded_files)[0] - uses: LizardByte/homebrew-release-action@v2024.1115.14934 + uses: LizardByte/homebrew-release-action@v2025.506.15440 with: formula_file: ${{ fromJson(steps.download.outputs.downloaded_files)[0] }} git_email: ${{ secrets.GH_BOT_EMAIL }} From 0bdc9188c344688d88b978871ef6f4debc02a695 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 May 2025 14:41:38 +0000 Subject: [PATCH 5/8] build(deps): bump vue from 3.5.13 to 3.5.14 (#3881) Bumps [vue](https://github.com/vuejs/core) from 3.5.13 to 3.5.14. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.13...v3.5.14) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10437904..b09df638 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@lizardbyte/shared-web": "2025.326.11214", - "vue": "3.5.13", + "vue": "3.5.14", "vue-i18n": "11.1.3" }, "devDependencies": { From ef5253a61dc3a5ee97776e5ff1ec26f302f4cc5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 May 2025 19:54:57 +0000 Subject: [PATCH 6/8] build(deps): bump third-party/build-deps from `b567d3c` to `d60197e` (#3900) build(deps): bump third-party/build-deps from `b567d3c` to `3a4ec78` Bumps [third-party/build-deps](https://github.com/LizardByte/build-deps) from `b567d3c` to `3a4ec78`. - [Commits](https://github.com/LizardByte/build-deps/compare/b567d3c47927c42c33ca86e87892269c354abc02...3a4ec7840a03fc1d297e943a070cca6c6de5d5b5) --- updated-dependencies: - dependency-name: third-party/build-deps dependency-version: 3a4ec7840a03fc1d297e943a070cca6c6de5d5b5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- third-party/build-deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/build-deps b/third-party/build-deps index b567d3c4..d60197e1 160000 --- a/third-party/build-deps +++ b/third-party/build-deps @@ -1 +1 @@ -Subproject commit b567d3c47927c42c33ca86e87892269c354abc02 +Subproject commit d60197e1543d63cc415ebe0225afd47025a819e2 From 3ad90cd7f1e872758341bf3c421984bbf0960ff0 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Sat, 24 May 2025 19:40:07 -0400 Subject: [PATCH 7/8] fix(installer/windows): remember service start type (#3902) --- .../windows/misc/service/install-service.bat | 33 ++++++++++++++++++- .../misc/service/uninstall-service.bat | 32 ++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src_assets/windows/misc/service/install-service.bat b/src_assets/windows/misc/service/install-service.bat index 03ce6e62..4ab85fe8 100644 --- a/src_assets/windows/misc/service/install-service.bat +++ b/src_assets/windows/misc/service/install-service.bat @@ -1,10 +1,13 @@ @echo off +setlocal enabledelayedexpansion rem Get sunshine root directory for %%I in ("%~dp0\..") do set "ROOT_DIR=%%~fI" set SERVICE_NAME=SunshineService -set SERVICE_BIN="%ROOT_DIR%\tools\sunshinesvc.exe" +set "SERVICE_BIN=%ROOT_DIR%\tools\sunshinesvc.exe" +set "SERVICE_CONFIG_DIR=%LOCALAPPDATA%\LizardByte\Sunshine" +set "SERVICE_CONFIG_FILE=%SERVICE_CONFIG_DIR%\service_start_type.txt" rem Set service to demand start. It will be changed to auto later if the user selected that option. set SERVICE_START_TYPE=demand @@ -26,6 +29,34 @@ if %ERRORLEVEL%==0 ( set SC_CMD=create ) +rem Check if we have a saved start type from previous installation +if exist "%SERVICE_CONFIG_FILE%" ( + rem Debug output file content + type "%SERVICE_CONFIG_FILE%" + + rem Read the saved start type + for /f "usebackq delims=" %%a in ("%SERVICE_CONFIG_FILE%") do ( + set "SAVED_START_TYPE=%%a" + ) + + echo Raw saved start type: [!SAVED_START_TYPE!] + + rem Check start type + if "!SAVED_START_TYPE!"=="2-delayed" ( + set SERVICE_START_TYPE=delayed-auto + ) else if "!SAVED_START_TYPE!"=="2" ( + set SERVICE_START_TYPE=auto + ) else if "!SAVED_START_TYPE!"=="3" ( + set SERVICE_START_TYPE=demand + ) else if "!SAVED_START_TYPE!"=="4" ( + set SERVICE_START_TYPE=disabled + ) + + del "%SERVICE_CONFIG_FILE%" +) + +echo Setting service start type set to: [!SERVICE_START_TYPE!] + rem Run the sc command to create/reconfigure the service sc %SC_CMD% %SERVICE_NAME% binPath= %SERVICE_BIN% start= %SERVICE_START_TYPE% DisplayName= "Sunshine Service" diff --git a/src_assets/windows/misc/service/uninstall-service.bat b/src_assets/windows/misc/service/uninstall-service.bat index 451ceb61..210468ee 100644 --- a/src_assets/windows/misc/service/uninstall-service.bat +++ b/src_assets/windows/misc/service/uninstall-service.bat @@ -1,4 +1,36 @@ @echo off +setlocal enabledelayedexpansion + +set "SERVICE_CONFIG_DIR=%LOCALAPPDATA%\LizardByte\Sunshine" +set "SERVICE_CONFIG_FILE=%SERVICE_CONFIG_DIR%\service_start_type.txt" + +rem Save the current service start type to a file if the service exists +sc qc SunshineService >nul 2>&1 +if %ERRORLEVEL%==0 ( + if not exist "%SERVICE_CONFIG_DIR%\" mkdir "%SERVICE_CONFIG_DIR%\" + + rem Get the start type + for /f "tokens=3" %%i in ('sc qc SunshineService ^| findstr /C:"START_TYPE"') do ( + set "CURRENT_START_TYPE=%%i" + ) + + rem Set the content to write + if "!CURRENT_START_TYPE!"=="2" ( + sc qc SunshineService | findstr /C:"(DELAYED)" >nul + if !ERRORLEVEL!==0 ( + set "CONTENT=2-delayed" + ) else ( + set "CONTENT=2" + ) + ) else if "!CURRENT_START_TYPE!" NEQ "" ( + set "CONTENT=!CURRENT_START_TYPE!" + ) else ( + set "CONTENT=unknown" + ) + + rem Write content to file + echo !CONTENT!> "%SERVICE_CONFIG_FILE%" +) rem Stop and delete the legacy SunshineSvc service net stop sunshinesvc From 673e0fa4f4462f6a27149e579f459861fbeb0154 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Sat, 24 May 2025 23:34:45 -0400 Subject: [PATCH 8/8] fix(installer/windows): ensure service_bin is properly quoted (#3904) --- src_assets/windows/misc/service/install-service.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_assets/windows/misc/service/install-service.bat b/src_assets/windows/misc/service/install-service.bat index 4ab85fe8..fcec2e66 100644 --- a/src_assets/windows/misc/service/install-service.bat +++ b/src_assets/windows/misc/service/install-service.bat @@ -58,7 +58,7 @@ if exist "%SERVICE_CONFIG_FILE%" ( echo Setting service start type set to: [!SERVICE_START_TYPE!] rem Run the sc command to create/reconfigure the service -sc %SC_CMD% %SERVICE_NAME% binPath= %SERVICE_BIN% start= %SERVICE_START_TYPE% DisplayName= "Sunshine Service" +sc %SC_CMD% %SERVICE_NAME% binPath= "%SERVICE_BIN%" start= %SERVICE_START_TYPE% DisplayName= "Sunshine Service" rem Set the description of the service sc description %SERVICE_NAME% "Sunshine is a self-hosted game stream host for Moonlight."