Skip to content

Commit cc688c7

Browse files
authored
Implement process and thread priority adjustments (#691)
1 parent 997e8c6 commit cc688c7

8 files changed

Lines changed: 128 additions & 2 deletions

File tree

src/audio.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
8989
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
9090
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
9191

92+
// Encoding takes place on this thread
93+
platf::adjust_thread_priority(platf::thread_priority_e::high);
94+
9295
opus_t opus { opus_multistream_encoder_create(
9396
stream->sampleRate,
9497
stream->channelCount,
@@ -173,6 +176,9 @@ void capture(safe::mail_t mail, config_t config, void *channel_data) {
173176
}
174177
}
175178

179+
// Capture takes place on this thread
180+
platf::adjust_thread_priority(platf::thread_priority_e::critical);
181+
176182
auto samples = std::make_shared<sample_queue_t::element_type>(30);
177183
std::thread thread { encodeThread, samples, config, channel_data };
178184

src/platform/common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,18 @@ std::vector<std::string> display_names(mem_type_e hwdevice_type);
306306

307307
boost::process::child run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, boost::process::environment &env, FILE *file, std::error_code &ec);
308308

309+
enum class thread_priority_e : int {
310+
low,
311+
normal,
312+
high,
313+
critical
314+
};
315+
void adjust_thread_priority(thread_priority_e priority);
316+
317+
// Allow OS-specific actions to be taken to prepare for streaming
318+
void streaming_will_start();
319+
void streaming_will_stop();
320+
309321
input_t input();
310322
void move_mouse(input_t &input, int deltaX, int deltaY);
311323
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);

src/platform/linux/misc.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
153153
}
154154
}
155155

156+
void adjust_thread_priority(thread_priority_e priority) {
157+
// Unimplemented
158+
}
159+
160+
void streaming_will_start() {
161+
// Nothing to do
162+
}
163+
164+
void streaming_will_stop() {
165+
// Nothing to do
166+
}
167+
156168
namespace source {
157169
enum source_e : std::size_t {
158170
#ifdef SUNSHINE_BUILD_CUDA

src/platform/macos/misc.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
131131
}
132132
}
133133

134+
void adjust_thread_priority(thread_priority_e priority) {
135+
// Unimplemented
136+
}
137+
138+
void streaming_will_start() {
139+
// Nothing to do
140+
}
141+
142+
void streaming_will_stop() {
143+
// Nothing to do
144+
}
145+
134146
} // namespace platf
135147

136148
namespace dyn {

src/platform/windows/misc.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
#include <winuser.h>
1414
#include <ws2tcpip.h>
1515
#include <userenv.h>
16+
#include <dwmapi.h>
17+
#include <timeapi.h>
1618
// clang-format on
1719

1820
#include "src/main.h"
21+
#include "src/platform/common.h"
1922
#include "src/utility.h"
2023

2124
namespace bp = boost::process;
@@ -470,4 +473,53 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
470473
}
471474
}
472475

476+
void adjust_thread_priority(thread_priority_e priority) {
477+
int win32_priority;
478+
479+
switch(priority) {
480+
case thread_priority_e::low:
481+
win32_priority = THREAD_PRIORITY_BELOW_NORMAL;
482+
break;
483+
case thread_priority_e::normal:
484+
win32_priority = THREAD_PRIORITY_NORMAL;
485+
break;
486+
case thread_priority_e::high:
487+
win32_priority = THREAD_PRIORITY_ABOVE_NORMAL;
488+
break;
489+
case thread_priority_e::critical:
490+
win32_priority = THREAD_PRIORITY_HIGHEST;
491+
break;
492+
default:
493+
BOOST_LOG(error) << "Unknown thread priority: "sv << (int)priority;
494+
return;
495+
}
496+
497+
if(!SetThreadPriority(GetCurrentThread(), win32_priority)) {
498+
auto winerr = GetLastError();
499+
BOOST_LOG(warning) << "Unable to set thread priority to "sv << win32_priority << ": "sv << winerr;
500+
}
501+
}
502+
503+
void streaming_will_start() {
504+
// Enable MMCSS scheduling for DWM
505+
DwmEnableMMCSS(true);
506+
507+
// Reduce timer period to 1ms
508+
timeBeginPeriod(1);
509+
510+
// Promote ourselves to high priority class
511+
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
512+
}
513+
514+
void streaming_will_stop() {
515+
// Demote ourselves back to normal priority class
516+
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
517+
518+
// End our 1ms timer request
519+
timeEndPeriod(1);
520+
521+
// Disable MMCSS scheduling for DWM
522+
DwmEnableMMCSS(false);
523+
}
524+
473525
} // namespace platf

src/stream.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,8 @@ void controlBroadcastThread(control_server_t *server) {
740740
input::passthrough(session->input, std::move(plaintext));
741741
});
742742

743+
// This thread handles latency-sensitive control messages
744+
platf::adjust_thread_priority(platf::thread_priority_e::critical);
743745

744746
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
745747
while(!shutdown_event->peek()) {
@@ -905,6 +907,9 @@ void videoBroadcastThread(udp::socket &sock) {
905907
auto packets = mail::man->queue<video::packet_t>(mail::video_packets);
906908
auto timebase = boost::posix_time::microsec_clock::universal_time();
907909

910+
// Video traffic is sent on this thread
911+
platf::adjust_thread_priority(platf::thread_priority_e::high);
912+
908913
while(auto packet = packets->pop()) {
909914
if(shutdown_event->peek()) {
910915
break;
@@ -1079,6 +1084,9 @@ void audioBroadcastThread(udp::socket &sock) {
10791084
audio_packet->rtp.packetType = 97;
10801085
audio_packet->rtp.ssrc = 0;
10811086

1087+
// Audio traffic is sent on this thread
1088+
platf::adjust_thread_priority(platf::thread_priority_e::high);
1089+
10821090
while(auto packet = packets->pop()) {
10831091
if(shutdown_event->peek()) {
10841092
break;
@@ -1333,6 +1341,8 @@ void audioThread(session_t *session) {
13331341
}
13341342

13351343
namespace session {
1344+
std::atomic_uint running_sessions;
1345+
13361346
state_e state(session_t &session) {
13371347
return session.state.load(std::memory_order_relaxed);
13381348
}
@@ -1394,6 +1404,11 @@ void join(session_t &session) {
13941404
}
13951405
}
13961406

1407+
// If this is the last session, invoke the platform callbacks
1408+
if(--running_sessions == 0) {
1409+
platf::streaming_will_stop();
1410+
}
1411+
13971412
BOOST_LOG(debug) << "Session ended"sv;
13981413
}
13991414

@@ -1432,6 +1447,11 @@ int start(session_t &session, const std::string &addr_string) {
14321447

14331448
session.state.store(state_e::RUNNING, std::memory_order_relaxed);
14341449

1450+
// If this is the first session, invoke the platform callbacks
1451+
if(++running_sessions == 1) {
1452+
platf::streaming_will_start();
1453+
}
1454+
14351455
return 0;
14361456
}
14371457

src/video.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,9 @@ void captureThread(
673673
}
674674
}
675675

676+
// Capture takes place on this thread
677+
platf::adjust_thread_priority(platf::thread_priority_e::critical);
678+
676679
while(capture_ctx_queue->running()) {
677680
bool artificial_reinit = false;
678681

@@ -703,7 +706,10 @@ void captureThread(
703706
}
704707

705708
auto &next_img = *round_robin++;
706-
while(next_img.use_count() > 1) {}
709+
while(next_img.use_count() > 1) {
710+
// Sleep a bit to avoid starving the encoder threads
711+
std::this_thread::sleep_for(2ms);
712+
}
707713

708714
return next_img;
709715
},
@@ -1335,6 +1341,9 @@ void captureThreadSync() {
13351341
}
13361342
});
13371343

1344+
// Encoding and capture takes place on this thread
1345+
platf::adjust_thread_priority(platf::thread_priority_e::high);
1346+
13381347
while(encode_run_sync(synced_session_ctxs, ctx) == encode_e::reinit) {}
13391348
}
13401349

@@ -1367,6 +1376,9 @@ void capture_async(
13671376

13681377
auto touch_port_event = mail->event<input::touch_port_t>(mail::touch_port);
13691378

1379+
// Encoding takes place on this thread
1380+
platf::adjust_thread_priority(platf::thread_priority_e::high);
1381+
13701382
while(!shutdown_event->peek() && images->running()) {
13711383
// Wait for the main capture event when the display is being reinitialized
13721384
if(ref->reinit_event.peek()) {

tools/sunshinesvc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
271271
NULL,
272272
NULL,
273273
TRUE,
274-
ABOVE_NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
274+
CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
275275
NULL,
276276
NULL,
277277
(LPSTARTUPINFOW)&startup_info,

0 commit comments

Comments
 (0)