diff --git a/CMakeLists.txt b/CMakeLists.txt index 25c7109e..04171a47 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) 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": { diff --git a/src/stream.cpp b/src/stream.cpp index bf66ad79..4031dd76 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1327,7 +1327,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); @@ -1523,14 +1523,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 | @@ -1622,11 +1628,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(); @@ -1686,6 +1692,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); @@ -1705,7 +1713,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 diff --git a/src_assets/windows/misc/service/install-service.bat b/src_assets/windows/misc/service/install-service.bat index e81803ab..bd8e5371 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=ApolloService -set SERVICE_BIN="%ROOT_DIR%\tools\sunshinesvc.exe" +set "SERVICE_BIN=%ROOT_DIR%\tools\sunshinesvc.exe" +set "SERVICE_CONFIG_DIR=%LOCALAPPDATA%\SudoMaker\Apollo" +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,8 +29,36 @@ 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= "Apollo Service" +sc %SC_CMD% %SERVICE_NAME% binPath= "%SERVICE_BIN%" start= %SERVICE_START_TYPE% DisplayName= "Apollo Service" rem Set the description of the service sc description %SERVICE_NAME% "Apollo is a self-hosted game stream host for Moonlight." diff --git a/src_assets/windows/misc/service/uninstall-service.bat b/src_assets/windows/misc/service/uninstall-service.bat index cf09b995..a5ae664a 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%\SudoMaker\Apollo" +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 ApolloService >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 ApolloService ^| findstr /C:"START_TYPE"') do ( + set "CURRENT_START_TYPE=%%i" + ) + + rem Set the content to write + if "!CURRENT_START_TYPE!"=="2" ( + sc qc ApolloService | 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 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