|
|
.github/workflows/ci-homebrew.yml
|
+4
−0
|
@@ -61,6 +61,10 @@ - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Select Xcode 16.2 if: matrix.os_name == 'macos' && matrix.os_version == '14' run: sudo xcode-select --switch /Applications/Xcode_16.2.app
- name: Seed additional macOS TCC permissions if: runner.os == 'macOS' run: |
|
|
|
.github/workflows/ci-macos.yml
|
+4
−0
|
@@ -74,6 +74,10 @@ with: submodules: recursive
- name: Select Xcode 16.2 if: matrix.os == 'macos-14' run: sudo xcode-select --switch /Applications/Xcode_16.2.app
- name: Install dependencies timeout-minutes: 5 run: |
|
|
|
cmake/compile_definitions/common.cmake
|
+7
−1
|
@@ -25,11 +25,17 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-uninitialized) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") # Clang specific compile options
# Clang doesn't actually complain about this this, so disabling for now # list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-uninitialized)
# Some libc++ versions on Apple and FreeBSD guard std::jthread behind this flag. if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") list(APPEND SUNSHINE_COMPILE_OPTIONS -fexperimental-library) list(APPEND SUNSHINE_LINK_OPTIONS -fexperimental-library) endif() endif() if(BUILD_WERROR) list(APPEND SUNSHINE_COMPILE_OPTIONS -Werror)
|
|
|
cmake/targets/common.cmake
|
+1
−0
|
@@ -34,6 +34,7 @@ endif()
target_compile_options(sunshine PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301 target_link_options(sunshine PRIVATE ${SUNSHINE_LINK_OPTIONS})
# Homebrew build fails the vite build if we set these environment variables if(${SUNSHINE_BUILD_HOMEBREW})
|
|
|
cmake/targets/linux.cmake
|
+7
−4
|
@@ -2,8 +2,11 @@
if(NOT FREEBSD) # Using newer c++ compilers / features on older distros causes runtime dyn link errors list(APPEND SUNSHINE_EXTERNAL_LIBRARIES -static-libgcc -static-libstdc++ ) list(APPEND SUNSHINE_EXTERNAL_LIBRARIES -static-libgcc)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) list(APPEND SUNSHINE_EXTERNAL_LIBRARIES stdc++) else() list(APPEND SUNSHINE_EXTERNAL_LIBRARIES -static-libstdc++) endif() endif()
|
|
|
docs/building.md
|
+8
−0
|
@@ -28,6 +28,7 @@ devel/git \ devel/libevdev \ devel/libnotify \ devel/llvm19 \ devel/ninja \ devel/pkgconf \ devel/qt6-base \ @@ -46,6 +47,13 @@ x11/libXfixes \ x11/libXrandr \ x11/libXtst ```
Use LLVM 19 when configuring a local FreeBSD build:
```sh export CC=clang19 export CXX=clang++19 ```
#### Linux
|
|
|
packaging/linux/Arch/PKGBUILD
|
+1
−0
|
@@ -31,6 +31,7 @@ depends=( 'avahi' 'curl' 'gcc-libs' 'gtk3' 'hicolor-icon-theme' 'libayatana-appindicator'
|
|
|
packaging/sunshine.rb
|
+4
−0
|
@@ -59,6 +59,10 @@ depends_on "openssl@3" depends_on "opus"
on_sonoma do depends_on xcode: ["16.2", :build] # required for jthreads on macos-14 end
on_linux do depends_on GCC_FORMULA => [:build, :test] depends_on "gcovr" => [:build, :test]
|
|
|
src/audio.cpp
|
+1
−1
|
@@ -234,7 +234,7 @@ platf::adjust_thread_priority(platf::thread_priority_e::critical);
auto samples = std::make_shared<sample_queue_t::element_type>(30); std::thread thread {encodeThread, samples, config, channel_data}; std::jthread thread {encodeThread, samples, config, channel_data};
auto fg = util::fail_guard([&]() { samples->stop();
|
|
|
src/confighttp.cpp
|
+1
−1
|
@@ -1845,7 +1845,7 @@ return; } }; std::thread tcp {accept_and_run, &server}; std::jthread tcp {accept_and_run, &server};
// Wait for any event shutdown_event->view();
|
|
|
src/main.cpp
|
+4
−4
|
@@ -270,6 +270,6 @@ std::promise<void> session_monitor_join_thread_promise; auto session_monitor_join_thread_future = session_monitor_join_thread_promise.get_future();
std::thread session_monitor_thread([&]() { std::jthread session_monitor_thread([&]() { platf::set_thread_name("session_monitor"); session_monitor_join_thread_promise.set_value_at_thread_exit(); @@ -437,9 +437,9 @@ return lifetime::desired_exit_code; }
std::thread httpThread {nvhttp::start}; std::thread configThread {confighttp::start}; std::thread rtspThread {rtsp_stream::start}; std::jthread httpThread {nvhttp::start}; std::jthread configThread {confighttp::start}; std::jthread rtspThread {rtsp_stream::start};
#ifdef _WIN32 // If we're using the default port and GameStream is enabled, warn the user
|
|
|
src/nvhttp.cpp
|
+2
−2
|
@@ -1401,8 +1401,8 @@ return; } }; std::thread ssl {accept_and_run, &https_server}; std::thread tcp {accept_and_run, &http_server}; std::jthread ssl {accept_and_run, &https_server}; std::jthread tcp {accept_and_run, &http_server};
// Wait for any event shutdown_event->view();
|
|
|
src/platform/linux/audio.cpp
|
+2
−2
|
@@ -302,7 +302,7 @@ std::unique_ptr<safe::event_t<ctx_event_e>> events; ///< Event queue receiving PulseAudio context state changes. std::unique_ptr<std::function<void(ctx_t::pointer)>> events_cb; ///< Callback that translates PulseAudio context updates into events.
std::thread worker; ///< Thread running the PulseAudio mainloop. std::jthread worker; ///< Thread running the PulseAudio mainloop.
/** * @brief Initialize PulseAudio mainloop, context, and Sunshine null sinks. @@ -344,7 +344,7 @@ return -1; }
worker = std::thread { worker = std::jthread { [](loop_t::pointer loop) { int retval; platf::set_thread_name("audio::pulseaudio");
|
|
|
src/platform/linux/publish.cpp
|
+3
−3
|
@@ -529,13 +529,13 @@ */ class deinit_t: public ::platf::deinit_t { public: std::thread poll_thread; ///< Poll thread. std::jthread poll_thread; ///< Poll thread.
/** * @brief Store the Avahi polling thread for shutdown on destruction. * * @param poll_thread Poll thread. */ deinit_t(std::thread poll_thread): deinit_t(std::jthread poll_thread): poll_thread {std::move(poll_thread)} { } @@ -581,6 +581,6 @@ return nullptr; }
return std::make_unique<deinit_t>(std::jthread {avahi::simple_poll_loop, poll.get()}); return std::make_unique<deinit_t>(std::thread {avahi::simple_poll_loop, poll.get()}); } } // namespace platf::publish
|
|
|
src/platform/macos/publish.cpp
|
+2
−2
|
@@ -42,7 +42,7 @@ */ deinit_t(DNSServiceRef serviceRef): unique_ptr(serviceRef) { _thread = std::thread {[serviceRef, &_stopRequested = std::as_const(_stopRequested)]() { _thread = std::jthread {[serviceRef, &_stopRequested = std::as_const(_stopRequested)]() { platf::set_thread_name("publish::mdns"); const auto socket = DNSServiceRefSockFD(serviceRef); while (!_stopRequested) { @@ -74,6 +74,6 @@ deinit_t &operator=(const deinit_t &) = delete;
private: std::thread _thread; ///< Thread for polling the mDNS service for a response. std::jthread _thread; ///< Thread for polling the mDNS service for a response. std::atomic<bool> _stopRequested = false; ///< Whether to stop polling the mDNS service. };
|
|
|
src/rtsp.cpp
|
+1
−1
|
@@ -1349,6 +1349,6 @@ return; }
std::thread rtsp_thread {[&shutdown_event] { std::jthread rtsp_thread {[&shutdown_event] { platf::set_thread_name("rtsp::handler"); auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
|
|
src/stream.cpp
|
+12
−12
|
@@ -454,9 +454,9 @@ struct broadcast_ctx_t { message_queue_queue_t message_queue_queue; ///< Queues carrying encoded video and audio packets to sender threads.
std::thread recv_thread; ///< Thread that receives incoming control-channel messages. std::thread video_thread; ///< Thread that sends encoded video packets. std::thread audio_thread; ///< Thread that sends encoded audio packets. std::thread control_thread; ///< Thread that runs the ENet control server. std::jthread recv_thread; ///< Thread that receives incoming control-channel messages. std::jthread video_thread; ///< Thread that sends encoded video packets. std::jthread audio_thread; ///< Thread that sends encoded audio packets. std::jthread control_thread; ///< Thread that runs the ENet control server.
asio::io_context io_context; ///< Asio context used by the UDP broadcast sockets. @@ -477,7 +477,7 @@
std::shared_ptr<input::input_t> input; ///< Platform input device state for this stream.
std::thread audioThread; ///< Audio thread. std::thread videoThread; ///< Video thread. std::jthread audioThread; ///< Audio thread. std::jthread videoThread; ///< Video thread.
std::chrono::steady_clock::time_point pingTimeout; ///< Deadline for receiving the next client ping. @@ -1960,11 +1960,11 @@
ctx.message_queue_queue = std::make_shared<message_queue_queue_t::element_type>(30);
ctx.video_thread = std::thread {videoBroadcastThread, std::ref(ctx.video_sock)}; ctx.audio_thread = std::thread {audioBroadcastThread, std::ref(ctx.audio_sock)}; ctx.control_thread = std::thread {controlBroadcastThread, &ctx.control_server}; ctx.video_thread = std::jthread {videoBroadcastThread, std::ref(ctx.video_sock)}; ctx.audio_thread = std::jthread {audioBroadcastThread, std::ref(ctx.audio_sock)}; ctx.control_thread = std::jthread {controlBroadcastThread, &ctx.control_server};
ctx.recv_thread = std::thread {recvThread, std::ref(ctx)}; ctx.recv_thread = std::jthread {recvThread, std::ref(ctx)};
return 0; } @@ -2234,7 +2234,7 @@
session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
session.audioThread = std::thread {audioThread, &session}; session.videoThread = std::thread {videoThread, &session}; session.audioThread = std::jthread {audioThread, &session}; session.videoThread = std::jthread {videoThread, &session};
session.state.store(state_e::RUNNING, std::memory_order_relaxed);
|
|
|
src/system_tray.cpp
|
+1
−1
|
@@ -445,7 +445,7 @@
int init_tray_threaded() { try { auto tray_thread = std::thread(tray_thread_worker); auto tray_thread = std::jthread(tray_thread_worker);
// The tray thread doesn't require strong lifetime management. // It will exit asynchronously when tray_exit() is called.
|
|
|
src/thread_pool.h
|
+3
−3
|
@@ -23,7 +23,7 @@ typedef TaskPool::__task __task;
private: std::vector<std::thread> _thread; std::vector<std::jthread> _thread;
std::condition_variable _cv; std::mutex _lock; @@ -44,6 +44,6 @@ _thread(threads), _continue {true} { for (auto &t : _thread) { t = std::thread(&ThreadPool::_main, this); t = std::jthread(&ThreadPool::_main, this); } } @@ -113,6 +113,6 @@ _thread.resize(threads);
for (auto &t : _thread) { t = std::jthread(&ThreadPool::_main, this); t = std::thread(&ThreadPool::_main, this); } }
|
|
|
src/upnp.cpp
|
+2
−2
|
@@ -94,7 +94,7 @@ }
// Start the mapping thread upnp_thread = std::thread {&deinit_t::upnp_thread_proc, this}; upnp_thread = std::jthread {&deinit_t::upnp_thread_proc, this}; }
/** @@ -373,7 +373,7 @@ }
std::vector<mapping_t> mappings; ///< Port mappings Sunshine should keep registered with the gateway. std::thread upnp_thread; ///< Worker thread that refreshes mappings until shutdown. std::jthread upnp_thread; ///< Worker thread that refreshes mappings until shutdown. };
/**
|
|
|
src/video.cpp
|
+4
−4
|
@@ -630,7 +630,7 @@ */ struct capture_thread_async_ctx_t { std::shared_ptr<safe::queue_t<capture_ctx_t>> capture_ctx_queue; ///< Capture ctx queue. std::thread capture_thread; ///< Capture thread. std::jthread capture_thread; ///< Capture thread.
safe::signal_t reinit_event; ///< Reinit event. const encoder_t *encoder_p; ///< Encoder p. @@ -2354,7 +2354,7 @@ // streaming to continue without requiring a full restart of Sunshine. auto fail_guard = util::fail_guard([&encoder, &session] { if (encoder.flags & ASYNC_TEARDOWN) { std::thread encoder_teardown_thread {[session = std::move(session)]() mutable { std::jthread encoder_teardown_thread {[session = std::move(session)]() mutable { BOOST_LOG(info) << "Starting async encoder teardown"; session.reset(); BOOST_LOG(info) << "Async encoder teardown complete"; @@ -3593,7 +3593,7 @@
capture_thread_ctx.capture_ctx_queue = std::make_shared<safe::queue_t<capture_ctx_t>>(30);
capture_thread_ctx.capture_thread = std::thread { capture_thread_ctx.capture_thread = std::jthread { captureThread, capture_thread_ctx.capture_ctx_queue, std::ref(capture_thread_ctx.display_wp), @@ -3617,6 +3617,6 @@ * @brief Start capture sync. */ int start_capture_sync(capture_thread_sync_ctx_t &ctx) { std::thread {&captureThreadSync}.detach(); std::jthread {&captureThreadSync}.detach(); return 0; }
|
|
|
tests/CMakeLists.txt
|
+1
−1
|
@@ -181,7 +181,7 @@ target_link_libraries(${PROJECT_NAME} ${TEST_LINK_LIBRARIES}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${SUNSHINE_DEFINITIONS} ${TEST_DEFINITIONS}) target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301 target_link_options(${PROJECT_NAME} PRIVATE) target_link_options(${PROJECT_NAME} PRIVATE ${SUNSHINE_LINK_OPTIONS})
if (WIN32) # prefer static libraries since we're linking statically
|
|
|
tests/unit/test_audio.cpp
|
+2
−2
|
@@ -42,7 +42,7 @@ );
TEST_P(AudioTest, TestEncode) { std::thread timer([&] { std::jthread timer([&] { // Terminate the audio capture after 100 ms std::this_thread::sleep_for(100ms); const auto shutdown_event = m_mail->event<bool>(mail::shutdown); @@ -50,7 +50,7 @@ shutdown_event->raise(true); audio_packets->stop(); }); std::thread capture([&] { std::jthread capture([&] { const auto packets = m_mail->queue<packet_t>(mail::audio_packets); const auto shutdown_event = m_mail->event<bool>(mail::shutdown); while (const auto packet = packets->pop()) {
|
|
|
tests/unit/test_confighttp.cpp
|
+2
−2
|
@@ -93,7 +93,7 @@ protected: std::unique_ptr<SimpleWeb::Server<SimpleWeb::HTTPS>> server; std::unique_ptr<SimpleWeb::Client<SimpleWeb::HTTPS>> client; std::thread server_thread; // NOSONAR(cpp:S6168) - jthread not available on FreeBSD 14.3 libc++ std::jthread server_thread; unsigned short port = 0;
std::string saved_username; @@ -310,7 +310,7 @@ };
// Start server server_thread = std::thread([this]() { // NOSONAR(cpp:S6168) - jthread not available on FreeBSD 14.3 libc++ server_thread = std::jthread([this]() { server->start([this](const unsigned short assigned_port) { port = assigned_port; });
|