[feat] display video codecs and refine network statistics

This commit is contained in:
dijunkun
2026-10-22 19:18:37 +08:00
parent 193dcc4be0
commit c6a2f6a35b
15 changed files with 247 additions and 48 deletions
@@ -199,6 +199,7 @@ void GuiRuntime::HandleServerControllerDisconnected(
remote_input_.Disconnect(remote_id);
devices_.OnControllerConnectionsChanged();
connection_host_names_.erase(remote_id);
codec_status_controllers_.erase(remote_id);
privacy_sessions_.Disconnected(remote_id);
for (const auto& [id, status] : connection_status_) {
if (status != ConnectionStatus::Connected) {
@@ -8,6 +8,9 @@
#define _NET_TRAFFIC_STATS_CACHE_H_
#include <atomic>
#include <cstring>
#include <mutex>
#include <string>
#include "minirtc.h"
#include "runtime/connection_latency.h"
@@ -15,7 +18,8 @@
namespace crossdesk::gui_detail {
// Fields are independent observations and may come from different reports.
// Relaxed accesses keep each field safe without publishing any other state.
// Relaxed accesses keep scalar fields safe without publishing other state;
// codec names are copied under their own mutex.
class NetTrafficStatsCache {
static_assert(std::atomic<uint32_t>::is_always_lock_free &&
std::atomic<float>::is_always_lock_free &&
@@ -26,7 +30,31 @@ class NetTrafficStatsCache {
public:
using Clock = std::chrono::steady_clock;
struct VideoCodecNames {
std::string remote_encoder;
std::string local_decoder;
};
void StoreRemoteVideoEncoder(const std::string& encoder) {
std::lock_guard lock(codec_mutex_);
codecs_.remote_encoder = encoder;
}
VideoCodecNames LoadVideoCodecs() const {
std::lock_guard lock(codec_mutex_);
return codecs_;
}
void Store(const MiniRtcNetTrafficStats& stats) {
{
std::lock_guard lock(codec_mutex_);
local_encoder_.assign(
stats.video_encoder,
strnlen(stats.video_encoder, sizeof(stats.video_encoder)));
codecs_.local_decoder.assign(
stats.video_decoder,
strnlen(stats.video_decoder, sizeof(stats.video_decoder)));
}
video_inbound_stats_.Store(stats.video_inbound_stats);
video_outbound_stats_.Store(stats.video_outbound_stats);
audio_inbound_stats_.Store(stats.audio_inbound_stats);
@@ -46,6 +74,11 @@ class NetTrafficStatsCache {
MiniRtcNetTrafficStats Load() const {
MiniRtcNetTrafficStats stats{};
{
std::lock_guard lock(codec_mutex_);
local_encoder_.copy(stats.video_encoder, sizeof(stats.video_encoder) - 1);
codecs_.local_decoder.copy(stats.video_decoder, sizeof(stats.video_decoder) - 1);
}
stats.video_inbound_stats = video_inbound_stats_.Load();
stats.video_outbound_stats = video_outbound_stats_.Load();
stats.audio_inbound_stats = audio_inbound_stats_.Load();
@@ -80,6 +113,10 @@ class NetTrafficStatsCache {
void Reset() {
Store(MiniRtcNetTrafficStats{});
{
std::lock_guard lock(codec_mutex_);
codecs_ = {};
}
ResetLatency();
last_report_ms_.store(0, std::memory_order_relaxed);
}
@@ -130,6 +167,9 @@ class NetTrafficStatsCache {
std::atomic<double> rtt_ms_{-1};
std::atomic<int64_t> last_report_ms_{0};
ConnectionLatencyStats connection_latency_;
mutable std::mutex codec_mutex_;
std::string local_encoder_;
VideoCodecNames codecs_;
};
} // namespace crossdesk::gui_detail
@@ -209,6 +209,16 @@ void PeerEventHandler::OnReceiveDataBuffer(
return;
}
if (remote_action.type == ControlType::video_codec_status) {
if (auto props = runtime->FindRemoteSession(remote_id);
props && source_id == props->control_data_label_ &&
!props->closing_ &&
props->connection_status_ == ConnectionStatus::Connected) {
props->net_traffic_stats_.StoreRemoteVideoEncoder(remote_action.vcs.encoder);
}
return;
}
if (remote_action.type == ControlType::video_settings_status) {
if (auto props = runtime->FindRemoteSession(remote_id)) {
if (source_id != props->control_data_label_) return;
@@ -426,6 +436,12 @@ void PeerEventHandler::OnReceiveDataBuffer(
{
std::unique_lock lock(runtime->connection_status_mutex_);
runtime->connection_host_names_[remote_id] = host_name;
if (source_id == runtime->control_data_label_) {
if (remote_action.i.supports_video_codec_status)
runtime->codec_status_controllers_.insert(remote_id);
else
runtime->codec_status_controllers_.erase(remote_id);
}
}
LOG_INFO("Remote hostname: [{}]", host_name);
if (source_id == runtime->control_data_label_) {
@@ -5,6 +5,7 @@
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
@@ -295,6 +296,7 @@ void PeerEventHandler::OnConnectionStatus(ConnectionStatus status,
/*supports_privacy_screen=*/!runtime->unattended_host_,
CROSSDESK_VERSION, kClientPlatform);
remote_action.i.supports_video_settings = true;
remote_action.i.supports_video_codec_status = true;
remote_action.i.supports_text_input = runtime->devices_.SupportsTextInput();
remote_action.i.supports_deskhub_preview = true;
remote_action.i.supports_deskhub_resolution = true;
@@ -460,6 +462,7 @@ void PeerEventHandler::OnConnectionStatus(ConnectionStatus status,
/*supports_privacy_screen=*/!runtime->unattended_host_,
CROSSDESK_VERSION, kClientPlatform);
remote_action.i.supports_video_settings = true;
remote_action.i.supports_video_codec_status = true;
remote_action.i.supports_text_input = runtime->devices_.SupportsTextInput();
remote_action.i.supports_deskhub_preview = true;
remote_action.i.supports_deskhub_resolution = true;
@@ -577,7 +580,29 @@ void PeerEventHandler::OnNetStatusReport(
std::string remote_id(user_id, user_id_size);
auto props = runtime->FindRemoteSession(remote_id);
if (!props) return;
if (!props) {
bool report_codecs = false;
{
std::shared_lock lock(runtime->connection_status_mutex_);
const auto status = runtime->connection_status_.find(remote_id);
report_codecs = runtime->codec_status_controllers_.count(remote_id) != 0 &&
status != runtime->connection_status_.end() &&
status->second == ConnectionStatus::Connected;
}
if (net_traffic_stats && report_codecs) {
RemoteAction action{};
action.type = ControlType::video_codec_status;
std::snprintf(action.vcs.encoder, sizeof(action.vcs.encoder), "%.*s",
static_cast<int>(sizeof(net_traffic_stats->video_encoder)),
net_traffic_stats->video_encoder);
const auto message = action.to_json();
// Report only to this controller, after releasing the status lock.
SendReliableDataFrameToPeer(runtime->peer_, message.data(), message.size(),
runtime->control_data_label_.c_str(),
remote_id.data(), remote_id.size());
}
return;
}
if (props->traversal_mode_ != mode) {
props->net_traffic_stats_.ResetLatency();
props->traversal_mode_ = mode;
@@ -18,6 +18,7 @@
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -206,6 +207,7 @@ struct ConnectionState {
std::shared_mutex connection_status_mutex_;
std::unordered_map<std::string, ConnectionStatus> connection_status_;
std::unordered_map<std::string, std::string> connection_host_names_;
std::unordered_set<std::string> codec_status_controllers_;
// Cursor position is sampled asynchronously after remote mouse input has
// been injected. Remember the input source so the sampled position is not
// immediately echoed back to that same controller as stale feedback.