[feat] add DeskHub stream controls and network status

This commit is contained in:
dijunkun
2026-10-13 10:45:48 +08:00
parent 73b4d0f645
commit 3bd0676672
28 changed files with 1266 additions and 259 deletions
+34 -6
View File
@@ -16,11 +16,20 @@ namespace crossdesk {
struct PreviewSubscription {
uint32_t request_id = 0;
int fps =
0; // 0 pauses encoding/delivery, 1 overview, 8 focus, 60 interactive.
0; // 0 pauses; 1/8 legacy previews; 15 negotiated preview; 60 interactive.
int quality = 0;
int frame_rate = 30;
int preference = 0;
bool audio = false;
// v2 bounds are physical pixels. 0/0 restores the legacy source limit.
int width = 0;
int height = 0;
int version = 1;
static bool ValidResolution(int width, int height) {
return (width == 0 && height == 0) ||
(width >= 2 && height >= 2 && width <= 16384 && height <= 16384);
}
static PreviewSubscription Interactive(int quality, int frame_rate,
int preference, bool audio = false) {
@@ -31,24 +40,32 @@ struct PreviewSubscription {
return fps == other.fps && quality == other.quality &&
frame_rate == other.frame_rate &&
EncoderPreference() == other.EncoderPreference() &&
audio == other.audio;
audio == other.audio && width == other.width &&
height == other.height && version == other.version;
}
int EncoderPreference() const {
// Sparse preview input is intentional. Preserve spatial detail instead of
// applying the interactive frame-rate/keyframe latency budget to it.
return fps == 1 || fps == 8 ? 1 : preference;
return fps == 1 || fps == 8 || fps == 15 ? 1 : preference;
}
nlohmann::json ToJson() const {
return {{"type", "deskhub_preview"}, {"version", 1},
nlohmann::json json = {{"type", "deskhub_preview"}, {"version", version},
{"request_id", request_id}, {"fps", fps},
{"quality", quality}, {"frame_rate", frame_rate},
{"preference", EncoderPreference()}, {"audio", audio}};
if (version == 2) {
json["width"] = width;
json["height"] = height;
}
return json;
}
static std::optional<PreviewSubscription> Parse(const nlohmann::json &json) {
try {
if (json.at("type") != "deskhub_preview" || json.at("version") != 1)
if (json.at("type") != "deskhub_preview" ||
!json.at("version").is_number_integer() ||
(json.at("version") != 1 && json.at("version") != 2))
return {};
for (const char *key :
{"request_id", "fps", "quality", "frame_rate", "preference"})
@@ -66,7 +83,7 @@ struct PreviewSubscription {
json.at("quality"), json.at("frame_rate"),
json.at("preference")};
if ((result.fps != 0 && result.fps != 1 && result.fps != 8 &&
result.fps != 60) ||
result.fps != 15 && result.fps != 60) ||
result.quality < 0 || result.quality > 2 ||
(result.frame_rate != 30 && result.frame_rate != 60) ||
result.preference < 0 || result.preference > 2)
@@ -76,6 +93,17 @@ struct PreviewSubscription {
return {};
result.audio = json.at("audio").get<bool>();
}
result.version = json.at("version").get<int>();
if (result.version == 2) {
for (const char *key : {"width", "height"}) {
if (!json.at(key).is_number_integer()) return {};
const auto value = json.at(key).get<int64_t>();
if (value < 0 || value > 16384) return {};
}
result.width = json.at("width").get<int>();
result.height = json.at("height").get<int>();
if (!ValidResolution(result.width, result.height)) return {};
}
return result;
} catch (...) {
return {};
+2
View File
@@ -138,6 +138,8 @@ struct HostInfo {
bool supports_privacy_screen;
bool supports_video_settings;
bool supports_deskhub_preview;
bool supports_deskhub_resolution;
bool supports_deskhub_fps15;
};
struct ServiceStatus {
+9 -1
View File
@@ -27,6 +27,8 @@ void ResetHostInfo(HostInfo& info) {
info.supports_privacy_screen = false;
info.supports_video_settings = false;
info.supports_deskhub_preview = false;
info.supports_deskhub_resolution = false;
info.supports_deskhub_fps15 = false;
}
bool AllocateHostDisplays(HostInfo& info, std::size_t count) {
@@ -221,7 +223,9 @@ std::string RemoteAction::ToJson(const RemoteAction& action) {
{"displays", displays},
{"supports_privacy_screen", action.i.supports_privacy_screen},
{"supports_video_settings", action.i.supports_video_settings},
{"supports_deskhub_preview", action.i.supports_deskhub_preview}};
{"supports_deskhub_preview", action.i.supports_deskhub_preview},
{"supports_deskhub_resolution", action.i.supports_deskhub_resolution},
{"supports_deskhub_fps15", action.i.supports_deskhub_fps15}};
break;
}
case ControlType::invalid:
@@ -416,6 +420,10 @@ bool RemoteAction::FromJson(const std::string& json_string,
host_info_object.value("supports_video_settings", false);
output.i.supports_deskhub_preview =
host_info_object.value("supports_deskhub_preview", false);
output.i.supports_deskhub_resolution =
host_info_object.value("supports_deskhub_resolution", false);
output.i.supports_deskhub_fps15 =
host_info_object.value("supports_deskhub_fps15", false);
const std::string host_name =
host_info_object.at("host_name").get<std::string>();
std::strncpy(output.i.host_name, host_name.c_str(),