feat(linux): use connector name as default display name on linux (#5423)
This commit is contained in:
@@ -948,7 +948,8 @@ editing the `conf` file in a text editor. Use the examples as reference.
|
|||||||
Info: Detected display: DP-1 (id: 3) connected: false
|
Info: Detected display: DP-1 (id: 3) connected: false
|
||||||
Info: Detected display: DVI-D-1 (id: 4) connected: false
|
Info: Detected display: DVI-D-1 (id: 4) connected: false
|
||||||
@endcode
|
@endcode
|
||||||
You need to use the id value inside the parenthesis, e.g. `1`.
|
It is recommended to use the stable display connector name (text right before the parenthesis, e.g. DP-0) for this value.
|
||||||
|
For wlgrab/x11grab and kmsgrab the numeric id value can also be used.
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
**macOS:**
|
**macOS:**
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <ranges>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -848,6 +849,38 @@ namespace platf {
|
|||||||
BOOST_LOG(debug) << ss.str();
|
BOOST_LOG(debug) << ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Map display name to monitor index
|
||||||
|
*
|
||||||
|
* @param display_name Name of the display to determine monitor index for (or monitor index string value)
|
||||||
|
* @return monitor's display index
|
||||||
|
*/
|
||||||
|
static int64_t map_display_name_to_monitor_index(const std::string_view &display_name) {
|
||||||
|
// Handle (legacy) monitor index strings by converting them to integer
|
||||||
|
if (display_name.empty() || std::ranges::all_of(display_name, ::isdigit)) {
|
||||||
|
return util::from_view(display_name);
|
||||||
|
}
|
||||||
|
// display_name is a connector name (not empty and containing non-digits) try to resolve correct monitor index like correlate_wayland does
|
||||||
|
auto index_begin = display_name.find_last_of('-');
|
||||||
|
std::int64_t index;
|
||||||
|
if (index_begin == std::string_view::npos) {
|
||||||
|
index = 1;
|
||||||
|
} else {
|
||||||
|
index = std::max<int64_t>(1, util::from_view(display_name.substr(index_begin + 1)));
|
||||||
|
}
|
||||||
|
auto type = kms::from_view(display_name.substr(0, index_begin));
|
||||||
|
for (auto &card_descriptor : kms::card_descriptors) {
|
||||||
|
for (const auto &monitor_descriptor : card_descriptor.crtc_to_monitor | std::views::values) {
|
||||||
|
if (monitor_descriptor.type == type && monitor_descriptor.index == index) {
|
||||||
|
BOOST_LOG(debug) << "Mapped '"sv << display_name << "' to a monitor index " << monitor_descriptor.monitor_index;
|
||||||
|
return monitor_descriptor.monitor_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOST_LOG(warning) << "Couldn't map '"sv << display_name << "' to a monitor index. Falling back to first monitor in list (index=0).";
|
||||||
|
return 0; // Fallback to first index if nothing can be matched
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base KMS display capture backend shared by RAM and VRAM paths.
|
* @brief Base KMS display capture backend shared by RAM and VRAM paths.
|
||||||
*/
|
*/
|
||||||
@@ -873,7 +906,7 @@ namespace platf {
|
|||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
delay = ::video::capture_frame_interval(config);
|
delay = ::video::capture_frame_interval(config);
|
||||||
|
|
||||||
int monitor_index = util::from_view(display_name);
|
int monitor_index = map_display_name_to_monitor_index(display_name);
|
||||||
int monitor = 0;
|
int monitor = 0;
|
||||||
|
|
||||||
fs::path card_dir {"/dev/dri"sv};
|
fs::path card_dir {"/dev/dri"sv};
|
||||||
@@ -2099,8 +2132,8 @@ namespace platf {
|
|||||||
kms::env_height = std::max(kms::env_height, (int) (crtc->y + crtc->height));
|
kms::env_height = std::max(kms::env_height, (int) (crtc->y + crtc->height));
|
||||||
|
|
||||||
kms::print(plane.get(), fb.get(), crtc.get());
|
kms::print(plane.get(), fb.get(), crtc.get());
|
||||||
|
display_names.emplace_back(std::format("{}-{}", drmModeGetConnectorTypeName(it->second.type), it->second.index));
|
||||||
display_names.emplace_back(std::to_string(count++));
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cds.emplace_back(kms::card_descriptor_t {
|
cds.emplace_back(kms::card_descriptor_t {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
// standard includes
|
// standard includes
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
// plaform includes
|
// plaform includes
|
||||||
@@ -506,47 +507,41 @@ namespace platf {
|
|||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
int streamedMonitor = -1;
|
int streamedMonitor = -1;
|
||||||
if (!display_name.empty()) {
|
if (!display_name.empty() && std::ranges::all_of(display_name, ::isdigit)) {
|
||||||
|
// Resolve (legacy) monitor index from display_name
|
||||||
streamedMonitor = (int) util::from_view(display_name);
|
streamedMonitor = (int) util::from_view(display_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamedMonitor != -1) {
|
screen_res_t screenr {x11::rr::GetScreenResources(xdisplay.get(), xwindow)};
|
||||||
BOOST_LOG(info) << "Configuring selected display ("sv << streamedMonitor << ") to stream"sv;
|
int output = screenr->noutput;
|
||||||
screen_res_t screenr {x11::rr::GetScreenResources(xdisplay.get(), xwindow)};
|
|
||||||
int output = screenr->noutput;
|
|
||||||
|
|
||||||
output_info_t result;
|
output_info_t result;
|
||||||
int monitor = 0;
|
bool result_found = false;
|
||||||
for (int x = 0; x < output; ++x) {
|
int monitor = 0;
|
||||||
output_info_t out_info {x11::rr::GetOutputInfo(xdisplay.get(), screenr.get(), screenr->outputs[x])};
|
for (int x = 0; x < output; ++x) {
|
||||||
if (out_info) {
|
output_info_t out_info {x11::rr::GetOutputInfo(xdisplay.get(), screenr.get(), screenr->outputs[x])};
|
||||||
if (monitor++ == streamedMonitor) {
|
if (out_info) {
|
||||||
result = std::move(out_info);
|
// Match monitor by index if a valid one is present, otherwise try to resolve by matching output name to display_name
|
||||||
break;
|
if ((streamedMonitor >= 0 && monitor == streamedMonitor) || (streamedMonitor < 0 && out_info->name == display_name)) {
|
||||||
}
|
result = std::move(out_info);
|
||||||
|
result_found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
monitor++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (result_found && result->crtc) {
|
||||||
BOOST_LOG(error) << "Could not stream display number ["sv << streamedMonitor << "], there are only ["sv << monitor << "] displays."sv;
|
crtc_info_t crt_info {x11::rr::GetCrtcInfo(xdisplay.get(), screenr.get(), result->crtc)};
|
||||||
return -1;
|
BOOST_LOG(info)
|
||||||
}
|
<< "Streaming display: "sv << result->name << " with res "sv << crt_info->width << 'x' << crt_info->height << " offset by "sv << crt_info->x << 'x' << crt_info->y;
|
||||||
|
|
||||||
if (result->crtc) {
|
width = crt_info->width;
|
||||||
crtc_info_t crt_info {x11::rr::GetCrtcInfo(xdisplay.get(), screenr.get(), result->crtc)};
|
height = crt_info->height;
|
||||||
BOOST_LOG(info)
|
offset_x = crt_info->x;
|
||||||
<< "Streaming display: "sv << result->name << " with res "sv << crt_info->width << 'x' << crt_info->height << " offset by "sv << crt_info->x << 'x' << crt_info->y;
|
offset_y = crt_info->y;
|
||||||
|
|
||||||
width = crt_info->width;
|
|
||||||
height = crt_info->height;
|
|
||||||
offset_x = crt_info->x;
|
|
||||||
offset_y = crt_info->y;
|
|
||||||
} else {
|
|
||||||
BOOST_LOG(warning) << "Couldn't get requested display info, defaulting to recording entire virtual desktop"sv;
|
|
||||||
width = xattr.width;
|
|
||||||
height = xattr.height;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
BOOST_LOG(warning) << "Couldn't get info for requested display ["sv << display_name << "], defaulting to recording entire virtual desktop"sv;
|
||||||
width = xattr.width;
|
width = xattr.width;
|
||||||
height = xattr.height;
|
height = xattr.height;
|
||||||
}
|
}
|
||||||
@@ -971,22 +966,16 @@ namespace platf {
|
|||||||
screen_res_t screenr {x11::rr::GetScreenResources(xdisplay.get(), xwindow)};
|
screen_res_t screenr {x11::rr::GetScreenResources(xdisplay.get(), xwindow)};
|
||||||
int output = screenr->noutput;
|
int output = screenr->noutput;
|
||||||
|
|
||||||
|
std::vector<std::string> names;
|
||||||
int monitor = 0;
|
int monitor = 0;
|
||||||
for (int x = 0; x < output; ++x) {
|
for (int x = 0; x < output; ++x) {
|
||||||
output_info_t out_info {x11::rr::GetOutputInfo(xdisplay.get(), screenr.get(), screenr->outputs[x])};
|
output_info_t out_info {x11::rr::GetOutputInfo(xdisplay.get(), screenr.get(), screenr->outputs[x])};
|
||||||
if (out_info) {
|
if (out_info) {
|
||||||
BOOST_LOG(info) << "Detected display: "sv << out_info->name << " (id: "sv << monitor << ")"sv << out_info->name << " connected: "sv << (out_info->connection == RR_Connected);
|
BOOST_LOG(info) << "Detected display: "sv << out_info->name << " (id: "sv << monitor++ << ")"sv << out_info->name << " connected: "sv << (out_info->connection == RR_Connected);
|
||||||
++monitor;
|
names.emplace_back(out_info->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> names;
|
|
||||||
names.reserve(monitor);
|
|
||||||
|
|
||||||
for (auto x = 0; x < monitor; ++x) {
|
|
||||||
names.emplace_back(std::to_string(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ const props = defineProps([
|
|||||||
])
|
])
|
||||||
|
|
||||||
const config = ref(props.config)
|
const config = ref(props.config)
|
||||||
const outputNamePlaceholder = (props.platform === 'windows') ? '{de9bb7e2-186e-505b-9e93-f48793333810}' : '0'
|
let _outputNamePlaceholder = '0';
|
||||||
|
if(props.platform === 'windows') {
|
||||||
|
_outputNamePlaceholder = '{de9bb7e2-186e-505b-9e93-f48793333810}';
|
||||||
|
} else if(props.platform === 'linux' || props.platform === 'freebsd') {
|
||||||
|
_outputNamePlaceholder = 'DP-0';
|
||||||
|
}
|
||||||
|
const outputNamePlaceholder = _outputNamePlaceholder; // NOSONAR(javascript:S1481,javascript:S1854): Constant used by vue.js binding for placeholder below
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -33,21 +39,19 @@ const outputNamePlaceholder = (props.platform === 'windows') ? '{de9bb7e2-186e-5
|
|||||||
<template #freebsd>
|
<template #freebsd>
|
||||||
<pre style="white-space: pre-line;">
|
<pre style="white-space: pre-line;">
|
||||||
Info: Detecting displays
|
Info: Detecting displays
|
||||||
Info: Detected display: DVI-D-0 (id: 0) connected: false
|
Info: Detected display: HDMI-A-1 connected: true
|
||||||
Info: Detected display: HDMI-0 (id: 1) connected: true
|
Info: Detected display: DP-1 connected: true
|
||||||
Info: Detected display: DP-0 (id: 2) connected: true
|
Info: Detected display: DP-2 connected: false
|
||||||
Info: Detected display: DP-1 (id: 3) connected: false
|
Info: Detected display: DVI-D-3 connected: false
|
||||||
Info: Detected display: DVI-D-1 (id: 4) connected: false
|
|
||||||
</pre>
|
</pre>
|
||||||
</template>
|
</template>
|
||||||
<template #linux>
|
<template #linux>
|
||||||
<pre style="white-space: pre-line;">
|
<pre style="white-space: pre-line;">
|
||||||
Info: Detecting displays
|
Info: Detecting displays
|
||||||
Info: Detected display: DVI-D-0 (id: 0) connected: false
|
Info: Detected display: HDMI-A-1 connected: true
|
||||||
Info: Detected display: HDMI-0 (id: 1) connected: true
|
Info: Detected display: DP-1 connected: true
|
||||||
Info: Detected display: DP-0 (id: 2) connected: true
|
Info: Detected display: DP-2 connected: false
|
||||||
Info: Detected display: DP-1 (id: 3) connected: false
|
Info: Detected display: DVI-D-3 connected: false
|
||||||
Info: Detected display: DVI-D-1 (id: 4) connected: false
|
|
||||||
</pre>
|
</pre>
|
||||||
</template>
|
</template>
|
||||||
<template #macos>
|
<template #macos>
|
||||||
|
|||||||
@@ -333,7 +333,8 @@
|
|||||||
"origin_web_ui_allowed_pc": "Only localhost may access Web UI",
|
"origin_web_ui_allowed_pc": "Only localhost may access Web UI",
|
||||||
"origin_web_ui_allowed_wan": "Anyone may access Web UI",
|
"origin_web_ui_allowed_wan": "Anyone may access Web UI",
|
||||||
"output_name": "Display Id",
|
"output_name": "Display Id",
|
||||||
"output_name_desc_unix": "During Sunshine startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
|
"output_name_desc_macos": "During Sunshine startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
|
||||||
|
"output_name_desc_unix": "During Sunshine startup, you should see the list of detected displays. Note: It is recommended to use the display's connector name (e.g. DP-0) but depending on the capture backend used other values may be possible (see documentation for details). Below is an example; the actual output can be found in the Troubleshooting tab.",
|
||||||
"output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Sunshine startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
|
"output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Sunshine startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
|
||||||
"packetsize": "Packet Size Limit",
|
"packetsize": "Packet Size Limit",
|
||||||
"packetsize_desc": "Limit the packet size to avoid fragmentation on a low MTU link. This helps reduce packet loss and micro-stuttering, while streaming over a layer 2 VPN to clients that cannot configure this value, e.g. Moonlight for Android/iOS. Reduce the bitrate when using low values. Values larger than 1456 require jumbo frames. Range: 0, 200-65535. A value of 0 will disable the limit.",
|
"packetsize_desc": "Limit the packet size to avoid fragmentation on a low MTU link. This helps reduce packet loss and micro-stuttering, while streaming over a layer 2 VPN to clients that cannot configure this value, e.g. Moonlight for Android/iOS. Reduce the bitrate when using low values. Values larger than 1456 require jumbo frames. Range: 0, 200-65535. A value of 0 will disable the limit.",
|
||||||
|
|||||||
Reference in New Issue
Block a user