App ordering support for legacy clients
This commit is contained in:
@@ -592,6 +592,7 @@ namespace config {
|
||||
"ipv4", // Address family
|
||||
platf::appdata().string() + "/sunshine.log", // log file
|
||||
false, // notify_pre_releases
|
||||
false, // legacy_ordering
|
||||
{}, // prep commands
|
||||
{}, // server commands
|
||||
};
|
||||
@@ -1284,6 +1285,7 @@ namespace config {
|
||||
bool_f(vars, "enable_discovery", sunshine.enable_discovery);
|
||||
bool_f(vars, "envvar_compatibility_mode", sunshine.envvar_compatibility_mode);
|
||||
bool_f(vars, "notify_pre_releases", sunshine.notify_pre_releases);
|
||||
bool_f(vars, "legacy_ordering", sunshine.legacy_ordering);
|
||||
|
||||
int port = sunshine.port;
|
||||
int_between_f(vars, "port"s, port, {1024 + nvhttp::PORT_HTTPS, 65535 - rtsp_stream::RTSP_SETUP_PORT});
|
||||
|
||||
@@ -280,6 +280,7 @@ namespace config {
|
||||
|
||||
std::string log_file;
|
||||
bool notify_pre_releases;
|
||||
bool legacy_ordering;
|
||||
std::vector<prep_cmd_t> prep_cmds;
|
||||
std::vector<server_cmd_t> server_cmds;
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "utility.h"
|
||||
#include "uuid.h"
|
||||
#include "video.h"
|
||||
#include "zwpad.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "platform/windows/virtual_display.h"
|
||||
@@ -1069,7 +1070,16 @@ namespace nvhttp {
|
||||
if (!!(named_cert_p->perm & PERM::_all_actions)) {
|
||||
auto current_appid = proc::proc.running();
|
||||
auto should_hide_inactive_apps = config::input.enable_input_only_mode && current_appid > 0 && current_appid != proc::input_only_app_id;
|
||||
for (auto &app : proc::proc.get_apps()) {
|
||||
|
||||
auto app_list = proc::proc.get_apps();
|
||||
|
||||
size_t bits;
|
||||
if (config::sunshine.legacy_ordering) {
|
||||
bits = zwpad::pad_width_for_count(app_list.size());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < app_list.size(); i++) {
|
||||
auto& app = app_list[i];
|
||||
auto appid = util::from_view(app.id);
|
||||
if (should_hide_inactive_apps) {
|
||||
if (
|
||||
@@ -1085,10 +1095,15 @@ namespace nvhttp {
|
||||
}
|
||||
}
|
||||
|
||||
auto app_name = app.name;
|
||||
if (config::sunshine.legacy_ordering) {
|
||||
zwpad::pad_for_ordering(app.name, bits, i);
|
||||
}
|
||||
|
||||
pt::ptree app_node;
|
||||
|
||||
app_node.put("IsHdrSupported"s, video::active_hevc_mode == 3 ? 1 : 0);
|
||||
app_node.put("AppTitle"s, app.name);
|
||||
app_node.put("AppTitle"s, app_name);
|
||||
app_node.put("UUID", app.uuid);
|
||||
app_node.put("IDX", app.idx);
|
||||
app_node.put("ID", app.id);
|
||||
|
||||
61
src/zwpad.h
Normal file
61
src/zwpad.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// zero_width_pad.hpp
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <bit> // std::bit_width – C++20
|
||||
#include <stdexcept>
|
||||
|
||||
namespace zwpad
|
||||
{
|
||||
// Two distinct zero-width characters.
|
||||
// U+200B ZERO WIDTH SPACE – “0”
|
||||
// U+200C ZERO WIDTH NON-JOINER – “1”
|
||||
inline constexpr char8_t ZW0[] = u8"\u200B";
|
||||
inline constexpr char8_t ZW1[] = u8"\u200C";
|
||||
|
||||
/// \brief Encode \p index with a fixed-width binary prefix made of
|
||||
/// zero-width code-points and append the original text.
|
||||
///
|
||||
/// \param text The payload you actually want to keep visible.
|
||||
/// \param padBits How many zero-width *digits* to prepend.
|
||||
/// (Usually: std::bit_width(count-1).)
|
||||
/// \param index Position in the ordered set, **0-based**.
|
||||
///
|
||||
/// \return A UTF-8 std::string whose first \p padBits characters are
|
||||
/// either U+200B or U+200C, followed by \p text.
|
||||
///
|
||||
/// The lexical order of the resulting strings corresponds to the
|
||||
/// numerical order of *index* because U+200B < U+200C.
|
||||
///
|
||||
inline std::string
|
||||
pad_for_ordering(std::string_view text,
|
||||
std::size_t padBits,
|
||||
std::size_t index)
|
||||
{
|
||||
if (padBits == 0)
|
||||
throw std::invalid_argument("padBits must be > 0");
|
||||
if (index >= (std::size_t{1} << padBits))
|
||||
throw std::out_of_range("index does not fit into padBits");
|
||||
|
||||
std::string out;
|
||||
out.reserve(padBits * 3 + text.size()); // each ZW char is 3-byte UTF-8
|
||||
|
||||
for (std::size_t bit = 0; bit < padBits; ++bit)
|
||||
{
|
||||
// Emit the *most* significant bit first.
|
||||
const bool one = (index >> (padBits - 1 - bit)) & 1;
|
||||
out += one ? reinterpret_cast<const char*>(ZW1)
|
||||
: reinterpret_cast<const char*>(ZW0);
|
||||
}
|
||||
out.append(text);
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Convenience: compute the minimal pad width from the total count.
|
||||
[[nodiscard]]
|
||||
inline std::size_t pad_width_for_count(std::size_t count)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count must be > 0");
|
||||
return std::bit_width(count - 1); // e.g. count==8 → 3 bits
|
||||
}
|
||||
} // namespace zwpad
|
||||
@@ -242,6 +242,8 @@
|
||||
"qp": 28,
|
||||
"min_threads": 2,
|
||||
"limit_framerate": "enabled",
|
||||
"envvar_compatibility_mode": "disabled",
|
||||
"legacy_ordering": "disabled",
|
||||
"hevc_mode": 0,
|
||||
"av1_mode": 0,
|
||||
"capture": "",
|
||||
|
||||
@@ -5,8 +5,7 @@ import Checkbox from "../../Checkbox.vue";
|
||||
|
||||
const props = defineProps([
|
||||
'platform',
|
||||
'config',
|
||||
'global_prep_cmd'
|
||||
'config'
|
||||
])
|
||||
|
||||
const config = ref(props.config)
|
||||
@@ -51,6 +50,14 @@ const config = ref(props.config)
|
||||
default="false"
|
||||
></Checkbox>
|
||||
|
||||
<!-- Legacy ordering -->
|
||||
<Checkbox class="mb-3"
|
||||
id="legacy_ordering"
|
||||
locale-prefix="config"
|
||||
v-model="config.legacy_ordering"
|
||||
default="false"
|
||||
></Checkbox>
|
||||
|
||||
<!-- HEVC Support -->
|
||||
<div class="mb-3">
|
||||
<label for="hevc_mode" class="form-label">{{ $t('config.hevc_mode') }}</label>
|
||||
|
||||
@@ -304,6 +304,8 @@
|
||||
"lan_encryption_mode_1": "Enabled for supported clients",
|
||||
"lan_encryption_mode_2": "Required for all clients",
|
||||
"lan_encryption_mode_desc": "This determines when encryption will be used when streaming over your local network. Encryption can reduce streaming performance, particularly on less powerful hosts and clients.",
|
||||
"legacy_ordering": "App ordering for legacy clients",
|
||||
"legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly.",
|
||||
"limit_framerate": "Limit capture framerate",
|
||||
"limit_framerate_desc": "Limit the framerate being captured to client requested framerate. May not run at full framerate if vsync is enabled and display refreshrate does not match requested framerate. Could cause lag on some clients if disabled.",
|
||||
"locale": "Locale",
|
||||
|
||||
@@ -299,6 +299,8 @@
|
||||
"lan_encryption_mode_1": "为支持的客户端启用",
|
||||
"lan_encryption_mode_2": "强制所有客户端使用",
|
||||
"lan_encryption_mode_desc": "这将决定在本地网络上进行流媒体传输时何时使用加密。加密会降低流媒体性能,尤其是在功能较弱的主机和客户端上。",
|
||||
"legacy_ordering": "过时客户端 APP 排序支持",
|
||||
"legacy_ordering_desc": "启用对过时客户端的 APP 排序支持。可能在某些无法正确处理 UTF8 编码的客户端/脚本上导致问题。",
|
||||
"limit_framerate": "限制捕获帧率",
|
||||
"limit_framerate_desc": "将捕获帧率限制到客户端请求的帧率。当启用垂直同步且显示器刷新率与客户端刷新率不匹配时可能会跑不满请求的帧率。若禁用,可能会在某些客户端上导致延迟。",
|
||||
"locale": "本地化",
|
||||
|
||||
Reference in New Issue
Block a user