Migrate virtual display config to new Display Device API
This commit is contained in:
@@ -417,8 +417,6 @@ namespace config {
|
||||
|
||||
video_t video {
|
||||
false, // headless_mode
|
||||
false, // follow_client_hdr
|
||||
true, // set_vdisplay_primary
|
||||
28, // qp
|
||||
|
||||
0, // hevc_mode
|
||||
@@ -1091,8 +1089,6 @@ namespace config {
|
||||
}
|
||||
|
||||
bool_f(vars, "headless_mode", video.headless_mode);
|
||||
bool_f(vars, "follow_client_hdr", video.follow_client_hdr);
|
||||
bool_f(vars, "set_vdisplay_primary", video.set_vdisplay_primary);
|
||||
int_f(vars, "qp", video.qp);
|
||||
int_between_f(vars, "hevc_mode", video.hevc_mode, { 0, 3 });
|
||||
int_between_f(vars, "av1_mode", video.av1_mode, { 0, 3 });
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
namespace config {
|
||||
struct video_t {
|
||||
bool headless_mode;
|
||||
bool follow_client_hdr;
|
||||
bool set_vdisplay_primary;
|
||||
// ffmpeg params
|
||||
int qp; // higher == more compression and less quality
|
||||
|
||||
|
||||
@@ -738,6 +738,24 @@ namespace display_device {
|
||||
return DD_DATA.sm_instance->execute([&output_name](auto &settings_iface) { return settings_iface.getDisplayName(output_name); });
|
||||
}
|
||||
|
||||
std::string
|
||||
map_display_name(const std::string &display_name) {
|
||||
std::lock_guard lock { DD_DATA.mutex };
|
||||
if (!DD_DATA.sm_instance) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto available_devices { DD_DATA.sm_instance->execute([](auto &settings_iface) { return settings_iface.enumAvailableDevices(); }) };
|
||||
|
||||
for (auto &i : available_devices) {
|
||||
if (i.m_display_name == display_name) {
|
||||
return i.m_device_id;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
configure_display(const config::video_t &video_config, const rtsp_stream::launch_session_t &session) {
|
||||
const auto result { parse_configuration(video_config, session) };
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace display_device {
|
||||
[[nodiscard]] std::string
|
||||
map_output_name(const std::string &output_name);
|
||||
|
||||
[[nodiscard]] std::string
|
||||
map_display_name(const std::string &display_name);
|
||||
|
||||
/**
|
||||
* @brief Configure the display device based on the user configuration and the session information.
|
||||
* @note This is a convenience method for calling similar method of a different signature.
|
||||
@@ -119,7 +122,7 @@ namespace display_device {
|
||||
* const auto result = reset_persistence();
|
||||
* @examples_end
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
bool
|
||||
reset_persistence();
|
||||
|
||||
/**
|
||||
|
||||
158
src/process.cpp
158
src/process.cpp
@@ -163,9 +163,6 @@ namespace proc {
|
||||
// Ensure starting from a clean slate
|
||||
terminate();
|
||||
|
||||
// Save the original output name in case we modify it temporary later
|
||||
std::string output_name_orig = config::video.output_name;
|
||||
|
||||
_app = app;
|
||||
_app_id = app_id;
|
||||
_launch_session = launch_session;
|
||||
@@ -191,17 +188,19 @@ namespace proc {
|
||||
render_height &= ~1;
|
||||
}
|
||||
|
||||
launch_session->width = render_width;
|
||||
launch_session->height = render_height;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool create_virtual_display = config::video.headless_mode || launch_session->virtual_display || _app.virtual_display;
|
||||
|
||||
this->initial_display = config::video.output_name;
|
||||
// Executed when returning from function
|
||||
auto fg = util::fail_guard([&]() {
|
||||
// Restore to user defined output name
|
||||
config::video.output_name = output_name_orig;
|
||||
config::video.output_name = this->initial_display;
|
||||
terminate();
|
||||
if (!create_virtual_display) {
|
||||
display_device::revert_configuration();
|
||||
}
|
||||
display_device::revert_configuration();
|
||||
});
|
||||
|
||||
if (create_virtual_display) {
|
||||
@@ -211,8 +210,6 @@ namespace proc {
|
||||
}
|
||||
|
||||
if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK) {
|
||||
std::wstring prevPrimaryDisplayName = VDISPLAY::getPrimaryDisplay();
|
||||
|
||||
// Try set the render adapter matching the capture adapter if user has specified one
|
||||
if (!config::video.adapter_name.empty()) {
|
||||
VDISPLAY::setRenderAdapterByName(platf::from_utf8(config::video.adapter_name));
|
||||
@@ -236,69 +233,26 @@ namespace proc {
|
||||
|
||||
BOOST_LOG(info) << "Virtual Display created at " << vdisplayName;
|
||||
|
||||
std::wstring currentPrimaryDisplayName = VDISPLAY::getPrimaryDisplay();
|
||||
|
||||
// Don't change display settings when no params are given
|
||||
if (launch_session->width && launch_session->height && launch_session->fps) {
|
||||
// Apply display settings
|
||||
VDISPLAY::changeDisplaySettings(vdisplayName.c_str(), render_width, render_height, launch_session->fps);
|
||||
}
|
||||
|
||||
bool shouldActuallySetPrimary = false;
|
||||
|
||||
// Determine if we need to set the virtual display as primary
|
||||
// Client request overrides local config
|
||||
bool shouldSetVDisplayPrimary = launch_session->virtual_display;
|
||||
if (!shouldSetVDisplayPrimary) {
|
||||
// App config overrides global config
|
||||
if (_app.virtual_display) {
|
||||
shouldSetVDisplayPrimary = _app.virtual_display_primary;
|
||||
} else {
|
||||
shouldSetVDisplayPrimary = config::video.set_vdisplay_primary;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldSetVDisplayPrimary) {
|
||||
shouldActuallySetPrimary = (currentPrimaryDisplayName != vdisplayName);
|
||||
} else {
|
||||
shouldActuallySetPrimary = (currentPrimaryDisplayName != prevPrimaryDisplayName);
|
||||
}
|
||||
|
||||
// Set primary display if needed
|
||||
if (shouldActuallySetPrimary) {
|
||||
auto disp = shouldSetVDisplayPrimary ? vdisplayName : prevPrimaryDisplayName;
|
||||
BOOST_LOG(info) << "Setting display " << disp << " primary";
|
||||
|
||||
if (!VDISPLAY::setPrimaryDisplay(disp.c_str())) {
|
||||
BOOST_LOG(info) << "Setting display " << disp << " primary failed! Are you using Windows 11 24H2?";
|
||||
}
|
||||
}
|
||||
|
||||
// Set virtual_display to true when everything went fine
|
||||
this->virtual_display = true;
|
||||
this->display_name = platf::to_utf8(vdisplayName);
|
||||
|
||||
if (config::video.headless_mode) {
|
||||
// When using headless mode, we don't care which display user configured to use.
|
||||
// So we always set output_name to the newly created virtual display as a workaround for
|
||||
// empty name when probing graphics cards.
|
||||
config::video.output_name = this->display_name;
|
||||
}
|
||||
// When using virtual display, we don't care which display user configured to use.
|
||||
// So we always set output_name to the newly created virtual display as a workaround for
|
||||
// empty name when probing graphics cards.
|
||||
|
||||
config::video.output_name = display_device::map_display_name(this->display_name);
|
||||
}
|
||||
} else {
|
||||
display_device::configure_display(config::video, *launch_session);
|
||||
}
|
||||
#else
|
||||
// Executed when returning from function
|
||||
auto fg = util::fail_guard([&]() {
|
||||
// Restore to user defined output name
|
||||
config::video.output_name = output_name_orig;
|
||||
terminate();
|
||||
display_device::revert_configuration();
|
||||
});
|
||||
#endif
|
||||
|
||||
display_device::configure_display(config::video, *launch_session);
|
||||
#endif
|
||||
|
||||
|
||||
// Probe encoders again before streaming to ensure our chosen
|
||||
// encoder matches the active GPU (which could have changed
|
||||
@@ -420,60 +374,8 @@ namespace proc {
|
||||
|
||||
_app_launch_time = std::chrono::steady_clock::now();
|
||||
|
||||
#ifdef _WIN32
|
||||
auto resetHDRThread = std::thread([this, enable_hdr = launch_session->enable_hdr]{
|
||||
// Windows doesn't seem to be able to set HDR correctly when a display is just connected / changed resolution,
|
||||
// so we have tooggle HDR for the virtual display manually after a delay.
|
||||
auto retryInterval = 200ms;
|
||||
while (is_changing_settings_going_to_fail()) {
|
||||
if (retryInterval > 2s) {
|
||||
BOOST_LOG(warning) << "Restoring HDR settings failed due to retry timeout!";
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(retryInterval);
|
||||
retryInterval *= 2;
|
||||
}
|
||||
|
||||
// We should have got the actual streaming display by now
|
||||
std::string currentDisplay = this->display_name;
|
||||
if (currentDisplay.empty()) {
|
||||
BOOST_LOG(warning) << "Not getting current display in time! HDR will not be toggled.";
|
||||
} else {
|
||||
auto currentDisplayW = platf::from_utf8(currentDisplay).c_str();
|
||||
|
||||
this->initial_display = currentDisplay;
|
||||
this->initial_hdr = VDISPLAY::getDisplayHDRByName(currentDisplayW);
|
||||
|
||||
if (config::video.follow_client_hdr) {
|
||||
if (!VDISPLAY::setDisplayHDRByName(currentDisplayW, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_hdr) {
|
||||
if (VDISPLAY::setDisplayHDRByName(currentDisplayW, true)) {
|
||||
BOOST_LOG(info) << "HDR enabled for display " << currentDisplay;
|
||||
} else {
|
||||
BOOST_LOG(info) << "HDR enable failed for display " << currentDisplay;
|
||||
}
|
||||
}
|
||||
} else if (this->initial_hdr) {
|
||||
if (VDISPLAY::setDisplayHDRByName(currentDisplayW, false) && VDISPLAY::setDisplayHDRByName(currentDisplayW, true)) {
|
||||
BOOST_LOG(info) << "HDR toggled successfully for display " << currentDisplay;
|
||||
} else {
|
||||
BOOST_LOG(info) << "HDR toggle failed for display " << currentDisplay;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resetHDRThread.detach();
|
||||
#endif
|
||||
|
||||
fg.disable();
|
||||
|
||||
// Restore to user defined output name
|
||||
config::video.output_name = output_name_orig;
|
||||
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
system_tray::update_tray_playing(_app.name);
|
||||
#endif
|
||||
@@ -561,36 +463,39 @@ namespace proc {
|
||||
|
||||
_pipe.reset();
|
||||
|
||||
#ifdef _WIN32
|
||||
if (config::video.follow_client_hdr && !this->initial_display.empty()) {
|
||||
if (VDISPLAY::setDisplayHDRByName(platf::from_utf8(this->initial_display).c_str(), this->initial_hdr)) {
|
||||
BOOST_LOG(info) << "HDR restored successfully for display " << this->initial_display;
|
||||
} else {
|
||||
BOOST_LOG(info) << "HDR restore failed for display " << this->initial_display;
|
||||
};
|
||||
}
|
||||
bool has_run = _app_id > 0;
|
||||
|
||||
if (vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK && _launch_session && this->virtual_display) {
|
||||
#ifdef _WIN32
|
||||
bool used_virtual_display = vDisplayDriverStatus == VDISPLAY::DRIVER_STATUS::OK && _launch_session && this->virtual_display;
|
||||
if (used_virtual_display) {
|
||||
if (VDISPLAY::removeVirtualDisplay(_launch_session->display_guid)) {
|
||||
BOOST_LOG(info) << "Virtual Display removed successfully";
|
||||
} else {
|
||||
BOOST_LOG(info) << "Virtual Display remove failed";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool has_run = _app_id > 0;
|
||||
|
||||
// Only show the Stopped notification if we actually have an app to stop
|
||||
// Since terminate() is always run when a new app has started
|
||||
if (proc::proc.get_last_run_app_name().length() > 0 && has_run) {
|
||||
if (used_virtual_display) {
|
||||
display_device::reset_persistence();
|
||||
} else {
|
||||
display_device::revert_configuration();
|
||||
}
|
||||
#else
|
||||
if (proc::proc.get_last_run_app_name().length() > 0 && has_run) {
|
||||
display_device::revert_configuration();
|
||||
#endif
|
||||
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
system_tray::update_tray_stopped(proc::proc.get_last_run_app_name());
|
||||
#endif
|
||||
|
||||
display_device::revert_configuration();
|
||||
}
|
||||
|
||||
// Restore output name to its original value
|
||||
config::video.output_name = initial_display;
|
||||
|
||||
_app_id = -1;
|
||||
display_name.clear();
|
||||
initial_hdr = false;
|
||||
@@ -937,7 +842,6 @@ namespace proc {
|
||||
auto wait_all = app_node.get_optional<bool>("wait-all"s);
|
||||
auto exit_timeout = app_node.get_optional<int>("exit-timeout"s);
|
||||
auto virtual_display = app_node.get_optional<bool>("virtual-display"s);
|
||||
auto virtual_display_primary = app_node.get_optional<bool>("virtual-display-primary"s);
|
||||
auto resolution_scale_factor = app_node.get_optional<int>("scale-factor"s);
|
||||
auto use_app_identity = app_node.get_optional<bool>("use-app-identity"s);
|
||||
|
||||
@@ -1012,7 +916,6 @@ namespace proc {
|
||||
ctx.wait_all = wait_all.value_or(true);
|
||||
ctx.exit_timeout = std::chrono::seconds { exit_timeout.value_or(5) };
|
||||
ctx.virtual_display = virtual_display.value_or(false);
|
||||
ctx.virtual_display_primary = virtual_display_primary.value_or(true);
|
||||
ctx.scale_factor = resolution_scale_factor.value_or(100);
|
||||
ctx.use_app_identity = use_app_identity.value_or(false);
|
||||
|
||||
@@ -1041,7 +944,6 @@ namespace proc {
|
||||
ctx.name = "Virtual Display";
|
||||
ctx.image_path = parse_env_val(this_env, "virtual_desktop.png");
|
||||
ctx.virtual_display = true;
|
||||
ctx.virtual_display_primary = true;
|
||||
ctx.scale_factor = 100;
|
||||
ctx.use_app_identity = false;
|
||||
|
||||
|
||||
@@ -277,16 +277,9 @@
|
||||
id="virtualDisplay"
|
||||
label="apps.virtual_display"
|
||||
desc="apps.virtual_display_desc"
|
||||
v-model="editForm['exclude-global-prep-cmd']"
|
||||
v-model="editForm['virtual-display']"
|
||||
default="false"
|
||||
></Checkbox>
|
||||
<!-- set virtual display to primary -->
|
||||
<div class="mb-3 form-check" v-if="platform === 'windows' && editForm['virtual-display'] == 'true'">
|
||||
<label for="virtualDisplayPrimary" class="form-check-label">{{ $t('apps.virtual_display_primary') }}</label>
|
||||
<input type="checkbox" class="form-check-input" id="virtualDisplayPrimary" v-model="editForm['virtual-display-primary']"
|
||||
true-value="true" false-value="false" />
|
||||
<div class="form-text">{{ $t('apps.virtual_display_primary_desc') }}</div>
|
||||
</div>
|
||||
<!-- use app identity -->
|
||||
<div class="mb-3 form-check">
|
||||
<label for="useAppIdentity" class="form-check-label">{{ $t('apps.use_app_identity') }}</label>
|
||||
@@ -414,7 +407,6 @@
|
||||
"prep-cmd": [],
|
||||
detached: [],
|
||||
"image-path": "",
|
||||
"virtual-display-primary": true,
|
||||
"scale-factor": "100",
|
||||
"use-app-identity": false
|
||||
}
|
||||
|
||||
@@ -183,9 +183,7 @@
|
||||
"auto_capture_sink": "enabled",
|
||||
"adapter_name": "",
|
||||
"output_name": "",
|
||||
"headless_mode": "disabled",
|
||||
"fallback_mode": "",
|
||||
"set_vdisplay_primary": "enabled",
|
||||
"dd_configuration_option": "verify_only",
|
||||
"dd_resolution_option": "auto",
|
||||
"dd_manual_resolution": "",
|
||||
|
||||
@@ -125,23 +125,17 @@ const validateFallbackMode = (event) => {
|
||||
<!-- Fallback Display Mode -->
|
||||
<div class="mb-3">
|
||||
<label for="fallback_mode" class="form-label">{{ $t('config.fallback_mode') }}</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="fallback_mode"
|
||||
v-model="config.fallback_mode"
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="fallback_mode"
|
||||
v-model="config.fallback_mode"
|
||||
placeholder="1920x1080x60"
|
||||
@input="validateFallbackMode"
|
||||
/>
|
||||
<div class="form-text">{{ $t('config.fallback_mode_desc') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check" v-if="platform === 'windows'">
|
||||
<input type="checkbox" class="form-check-input" id="follow_client_hdr" v-model="config.follow_client_hdr" true-value="enabled" false-value="disabled"/>
|
||||
<label for="follow_client_hdr" class="form-check-label">{{ $t('config.follow_client_hdr') }}</label>
|
||||
<div class="form-text pre-wrap">{{ $t('config.follow_client_hdr_desc') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Headless Mode -->
|
||||
<div class="mb-3 form-check" v-if="platform === 'windows'">
|
||||
<input type="checkbox" class="form-check-input" id="headless_mode" v-model="config.headless_mode" true-value="enabled" false-value="disabled"/>
|
||||
@@ -149,13 +143,6 @@ const validateFallbackMode = (event) => {
|
||||
<div class="form-text">{{ $t('config.headless_mode_desc') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Set VDisplay Primary -->
|
||||
<div class="mb-3 form-check" v-if="platform === 'windows'">
|
||||
<input type="checkbox" class="form-check-input" id="set_vdisplay_primary" v-model="config.set_vdisplay_primary" true-value="enabled" false-value="disabled"/>
|
||||
<label for="set_vdisplay_primary" class="form-check-label">{{ $t('config.set_vdisplay_primary') }}</label>
|
||||
<div class="form-text">{{ $t('config.set_vdisplay_primary_desc') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- SudoVDA Driver Status -->
|
||||
<div class="alert" :class="[vdisplay === '0' ? 'alert-success' : 'alert-warning']" v-if="platform === 'windows'">
|
||||
<i class="fa-solid fa-xl fa-circle-info"></i> SudoVDA Driver status: {{currentDriverStatus}}
|
||||
|
||||
@@ -55,12 +55,15 @@ function addRemappingEntry() {
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseOne">
|
||||
{{ $t('config.dd_options_header') }} {{ $t('dd_options_header_vdd_na') }}
|
||||
{{ $t('config.dd_options_header') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show"
|
||||
aria-labelledby="panelsStayOpen-headingOne">
|
||||
<div class="accordion-body">
|
||||
<div class="alert alert-info" v-if="platform === 'windows'">
|
||||
<i class="fa-solid fa-xl fa-circle-info"></i>{{ $t('config.dd_resolution_option_vdisplay_desc') }}
|
||||
</div>
|
||||
|
||||
<!-- Configuration option -->
|
||||
<div class="mb-3">
|
||||
|
||||
Reference in New Issue
Block a user