Skip to content

Commit ce52ba2

Browse files
committed
fix(windows): resolve disappearing cursor after KVM switch
1 parent c9e0bb8 commit ce52ba2

File tree

3 files changed

+20
-102
lines changed

3 files changed

+20
-102
lines changed

src/platform/linux/misc.cpp

Lines changed: 6 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,14 @@
1010

1111
// standard includes
1212
#include <fstream>
13-
#include <iomanip>
1413
#include <iostream>
15-
#include <sstream>
1614

1715
// platform includes
1816
#include <arpa/inet.h>
1917
#include <dlfcn.h>
2018
#include <ifaddrs.h>
21-
#include <netinet/in.h>
2219
#include <netinet/udp.h>
2320
#include <pwd.h>
24-
#include <sys/socket.h>
25-
26-
#ifdef __FreeBSD__
27-
#include <net/if_dl.h> // For sockaddr_dl, LLADDR, and AF_LINK
28-
#endif
2921

3022
// lib includes
3123
#include <boost/asio/ip/address.hpp>
@@ -49,16 +41,6 @@
4941
#define SUNSHINE_GNUC_EXTENSION
5042
#endif
5143

52-
#ifndef SOL_IP
53-
#define SOL_IP IPPROTO_IP
54-
#endif
55-
#ifndef SOL_IPV6
56-
#define SOL_IPV6 IPPROTO_IPV6
57-
#endif
58-
#ifndef SOL_UDP
59-
#define SOL_UDP IPPROTO_UDP
60-
#endif
61-
6244
using namespace std::literals;
6345
namespace fs = std::filesystem;
6446
namespace bp = boost::process::v1;
@@ -232,40 +214,6 @@ namespace platf {
232214

233215
std::string get_mac_address(const std::string_view &address) {
234216
auto ifaddrs = get_ifaddrs();
235-
236-
#ifdef __FreeBSD__
237-
// On FreeBSD, we need to find the interface name first, then look for its AF_LINK entry
238-
std::string interface_name;
239-
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
240-
if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
241-
interface_name = pos->ifa_name;
242-
break;
243-
}
244-
}
245-
246-
if (!interface_name.empty()) {
247-
// Find the AF_LINK entry for this interface to get MAC address
248-
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
249-
if (pos->ifa_addr && pos->ifa_addr->sa_family == AF_LINK &&
250-
interface_name == pos->ifa_name) {
251-
auto sdl = (struct sockaddr_dl *) pos->ifa_addr;
252-
auto mac = (unsigned char *) LLADDR(sdl);
253-
254-
// Format MAC address as XX:XX:XX:XX:XX:XX
255-
std::ostringstream mac_stream;
256-
mac_stream << std::hex << std::setfill('0');
257-
for (int i = 0; i < sdl->sdl_alen; i++) {
258-
if (i > 0) {
259-
mac_stream << ':';
260-
}
261-
mac_stream << std::setw(2) << (int) mac[i];
262-
}
263-
return mac_stream.str();
264-
}
265-
}
266-
}
267-
#else
268-
// On Linux, read MAC address from sysfs
269217
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
270218
if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
271219
std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address");
@@ -276,7 +224,6 @@ namespace platf {
276224
}
277225
}
278226
}
279-
#endif
280227

281228
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
282229
return "00:00:00:00:00:00"s;
@@ -323,6 +270,10 @@ namespace platf {
323270
}
324271
}
325272

273+
void enable_mouse_keys() {
274+
// Unimplemented
275+
}
276+
326277
void adjust_thread_priority(thread_priority_e priority) {
327278
// Unimplemented
328279
}
@@ -430,12 +381,7 @@ namespace platf {
430381
}
431382

432383
union {
433-
#ifdef IP_PKTINFO
434384
char buf[CMSG_SPACE(sizeof(uint16_t)) + std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
435-
#elif defined(IP_SENDSRCADDR)
436-
// FreeBSD uses IP_SENDSRCADDR with struct in_addr instead of IP_PKTINFO with struct in_pktinfo
437-
char buf[CMSG_SPACE(sizeof(uint16_t)) + std::max(CMSG_SPACE(sizeof(struct in_addr)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
438-
#endif
439385
struct cmsghdr alignment;
440386
} cmbuf = {}; // Must be zeroed for CMSG_NXTHDR()
441387

@@ -461,7 +407,6 @@ namespace platf {
461407
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
462408
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
463409
} else {
464-
#ifdef IP_PKTINFO
465410
struct in_pktinfo pktInfo;
466411

467412
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
@@ -474,18 +419,6 @@ namespace platf {
474419
pktinfo_cm->cmsg_type = IP_PKTINFO;
475420
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
476421
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
477-
#elif defined(IP_SENDSRCADDR)
478-
// FreeBSD uses IP_SENDSRCADDR with struct in_addr instead of IP_PKTINFO
479-
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
480-
struct in_addr src_addr = saddr_v4.sin_addr;
481-
482-
cmbuflen += CMSG_SPACE(sizeof(src_addr));
483-
484-
pktinfo_cm->cmsg_level = IPPROTO_IP;
485-
pktinfo_cm->cmsg_type = IP_SENDSRCADDR;
486-
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(src_addr));
487-
memcpy(CMSG_DATA(pktinfo_cm), &src_addr, sizeof(src_addr));
488-
#endif
489422
}
490423

491424
auto const max_iovs_per_msg = send_info.payload_buffers.size() + (send_info.headers ? 1 : 0);
@@ -578,8 +511,8 @@ namespace platf {
578511

579512
{
580513
// If GSO is not supported, use sendmmsg() instead.
581-
std::vector<struct mmsghdr> msgs(send_info.block_count);
582-
std::vector<struct iovec> iovs(send_info.block_count * (send_info.headers ? 2 : 1));
514+
struct mmsghdr msgs[send_info.block_count];
515+
struct iovec iovs[send_info.block_count * (send_info.headers ? 2 : 1)];
583516
int iov_idx = 0;
584517
for (size_t i = 0; i < send_info.block_count; i++) {
585518
msgs[i].msg_len = 0;
@@ -655,12 +588,7 @@ namespace platf {
655588
}
656589

657590
union {
658-
#ifdef IP_PKTINFO
659591
char buf[std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
660-
#elif defined(IP_SENDSRCADDR)
661-
// FreeBSD uses IP_SENDSRCADDR with struct in_addr instead of IP_PKTINFO with struct in_pktinfo
662-
char buf[std::max(CMSG_SPACE(sizeof(struct in_addr)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
663-
#endif
664592
struct cmsghdr alignment;
665593
} cmbuf;
666594

@@ -684,7 +612,6 @@ namespace platf {
684612
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
685613
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
686614
} else {
687-
#ifdef IP_PKTINFO
688615
struct in_pktinfo pktInfo;
689616

690617
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
@@ -697,18 +624,6 @@ namespace platf {
697624
pktinfo_cm->cmsg_type = IP_PKTINFO;
698625
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
699626
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
700-
#elif defined(IP_SENDSRCADDR)
701-
// FreeBSD uses IP_SENDSRCADDR with struct in_addr instead of IP_PKTINFO
702-
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
703-
struct in_addr src_addr = saddr_v4.sin_addr;
704-
705-
cmbuflen += CMSG_SPACE(sizeof(src_addr));
706-
707-
pktinfo_cm->cmsg_level = IPPROTO_IP;
708-
pktinfo_cm->cmsg_type = IP_SENDSRCADDR;
709-
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(src_addr));
710-
memcpy(CMSG_DATA(pktinfo_cm), &src_addr, sizeof(src_addr));
711-
#endif
712627
}
713628

714629
struct iovec iovs[2];
@@ -842,18 +757,13 @@ namespace platf {
842757
// reset SO_PRIORITY back to 0.
843758
//
844759
// 6 is the highest priority that can be used without SYS_CAP_ADMIN.
845-
#ifndef SO_PRIORITY
846-
// FreeBSD doesn't support SO_PRIORITY, so we skip this
847-
BOOST_LOG(debug) << "SO_PRIORITY not supported on this platform, skipping traffic priority setting";
848-
#else
849760
int priority = data_type == qos_data_type_e::audio ? 6 : 5;
850761
if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) == 0) {
851762
// Reset SO_PRIORITY to 0 when QoS is disabled
852763
reset_options.emplace_back(std::make_tuple(SOL_SOCKET, SO_PRIORITY, 0));
853764
} else {
854765
BOOST_LOG(error) << "Failed to set SO_PRIORITY: "sv << errno;
855766
}
856-
#endif
857767

858768
return std::make_unique<qos_t>(sockfd, reset_options);
859769
}

src/platform/macos/misc.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ void open_url(const std::string &url) {
210210
}
211211
}
212212

213+
void enable_mouse_keys() {
214+
// Unimplemented
215+
}
216+
213217
void adjust_thread_priority(thread_priority_e priority) {
214218
// Unimplemented
215219
}

src/video.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ namespace video {
897897
H264_ONLY | PARALLEL_ENCODING | ALWAYS_REPROBE | YUV444_SUPPORT
898898
};
899899

900-
#if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__)
900+
#ifdef __linux__
901901
encoder_t vaapi {
902902
"vaapi"sv,
903903
std::make_unique<encoder_platform_formats_avcodec>(
@@ -1032,7 +1032,7 @@ namespace video {
10321032
&quicksync,
10331033
&amdvce,
10341034
#endif
1035-
#if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__)
1035+
#ifdef __linux__
10361036
&vaapi,
10371037
#endif
10381038
#ifdef __APPLE__
@@ -1977,6 +1977,10 @@ namespace video {
19771977
}
19781978

19791979
session->request_normal_frame();
1980+
1981+
// While streaming check to see if the mouse is present and enable Mouse Keys to force the cursor to appear
1982+
// This is useful for KVM switch scenarios where mouse may disappear during streaming
1983+
platf::enable_mouse_keys();
19801984
}
19811985
}
19821986

@@ -2467,8 +2471,8 @@ namespace video {
24672471
encoder.av1.capabilities.set();
24682472

24692473
// First, test encoder viability
2470-
config_t config_max_ref_frames {1920, 1080, 60, 6000, 1000, 1, 1, 1, 0, 0, 0};
2471-
config_t config_autoselect {1920, 1080, 60, 6000, 1000, 1, 0, 1, 0, 0, 0};
2474+
config_t config_max_ref_frames {1920, 1080, 60, 1000, 1, 1, 1, 0, 0, 0};
2475+
config_t config_autoselect {1920, 1080, 60, 1000, 1, 0, 1, 0, 0, 0};
24722476

24732477
// If the encoder isn't supported at all (not even H.264), bail early
24742478
reset_display(disp, encoder.platform_formats->dev_type, output_name, config_autoselect);
@@ -2563,14 +2567,14 @@ namespace video {
25632567
{
25642568
// H.264 is special because encoders may support YUV 4:4:4 without supporting 10-bit color depth
25652569
if (encoder.flags & YUV444_SUPPORT) {
2566-
config_t config_h264_yuv444 {1920, 1080, 60, 6000, 1000, 1, 0, 1, 0, 0, 1};
2570+
config_t config_h264_yuv444 {1920, 1080, 60, 1000, 1, 0, 1, 0, 0, 1};
25672571
encoder.h264[encoder_t::YUV444] = disp->is_codec_supported(encoder.h264.name, config_h264_yuv444) &&
25682572
validate_config(disp, encoder, config_h264_yuv444) >= 0;
25692573
} else {
25702574
encoder.h264[encoder_t::YUV444] = false;
25712575
}
25722576

2573-
const config_t generic_hdr_config = {1920, 1080, 60, 6000, 1000, 1, 0, 3, 1, 1, 0};
2577+
const config_t generic_hdr_config = {1920, 1080, 60, 1000, 1, 0, 3, 1, 1, 0};
25742578

25752579
// Reset the display since we're switching from SDR to HDR
25762580
reset_display(disp, encoder.platform_formats->dev_type, output_name, generic_hdr_config);

0 commit comments

Comments
 (0)