Initial project snapshot
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/event.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/pointer.h>
|
||||
#include <freerdp/update.h>
|
||||
|
||||
#include "rdp_worker/cursor/cursor_adapter.hpp"
|
||||
#include "rdp_worker/common/logger.hpp"
|
||||
#include "rdp_worker/runtime/models.hpp"
|
||||
|
||||
namespace rdp_worker::freerdp_runtime {
|
||||
|
||||
class RdpRuntime {
|
||||
public:
|
||||
explicit RdpRuntime(std::shared_ptr<common::Logger> logger);
|
||||
~RdpRuntime();
|
||||
|
||||
bool Start(const runtime::ConnectionSpec& spec);
|
||||
void Disconnect(bool terminate);
|
||||
bool IsConnected() const;
|
||||
bool PumpEvents(std::chrono::milliseconds timeout);
|
||||
int DesktopWidth() const;
|
||||
int DesktopHeight() const;
|
||||
bool SendFocusEvent(bool focused);
|
||||
bool SendKeyboardInput(uint16_t scan_code, bool key_down, bool extended);
|
||||
bool SendMouseMove(double normalized_x, double normalized_y);
|
||||
bool SendMouseButton(const std::string& button, bool pressed, double normalized_x, double normalized_y);
|
||||
bool SendMouseWheel(int wheel_delta, bool horizontal, double normalized_x, double normalized_y);
|
||||
bool SetClipboardText(const std::string& text);
|
||||
void MarkInputAppliedForGraphicsTrace(const std::string& correlation_id);
|
||||
std::optional<runtime::RenderNotification> CaptureFullFrameNotification(
|
||||
const std::string& state,
|
||||
const std::string& capture_source);
|
||||
std::optional<runtime::RenderNotification> PopRenderNotification();
|
||||
std::optional<runtime::ClipboardNotification> PopClipboardNotification();
|
||||
const std::string& RenderQualityProfile() const;
|
||||
|
||||
void InstallRenderHooks();
|
||||
void RemoveRenderHooks();
|
||||
void EnqueueRenderNotification(const std::string& type, common::JsonObject payload);
|
||||
void OnBeginPaint(rdpContext* context);
|
||||
void OnEndPaint(rdpContext* context);
|
||||
void OnDesktopResize(rdpContext* context);
|
||||
void OnBitmapUpdate(rdpContext* context, const BITMAP_UPDATE* bitmap);
|
||||
void OnRefreshRect(rdpContext* context, BYTE count, const RECTANGLE_16* areas);
|
||||
void OnSurfaceBits(rdpContext* context, const SURFACE_BITS_COMMAND* surface_bits);
|
||||
void OnSurfaceFrameMarker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker);
|
||||
void OnSurfaceFrameBits(rdpContext* context, const SURFACE_BITS_COMMAND* surface_bits, bool first, bool last, UINT32 frame_id);
|
||||
void OnChannelConnected(rdpContext* context, ChannelConnectedEventArgs* event_args);
|
||||
void OnChannelDisconnected(rdpContext* context, ChannelDisconnectedEventArgs* event_args);
|
||||
void OnPointerPosition(rdpContext* context, const POINTER_POSITION_UPDATE* pointer_position);
|
||||
void OnPointerSystem(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer_system);
|
||||
void OnPointerColor(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color);
|
||||
void OnPointerNew(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new);
|
||||
void OnPointerCached(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached);
|
||||
void OnPointerLarge(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large);
|
||||
UINT OnCliprdrServerCapabilities(CliprdrClientContext* context, const CLIPRDR_CAPABILITIES* capabilities);
|
||||
UINT OnCliprdrMonitorReady(CliprdrClientContext* context, const CLIPRDR_MONITOR_READY* monitor_ready);
|
||||
UINT OnCliprdrServerFormatList(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST* format_list);
|
||||
UINT OnCliprdrServerFormatListResponse(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST_RESPONSE* response);
|
||||
UINT OnCliprdrServerLockClipboardData(CliprdrClientContext* context, const CLIPRDR_LOCK_CLIPBOARD_DATA* lock_data);
|
||||
UINT OnCliprdrServerUnlockClipboardData(CliprdrClientContext* context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlock_data);
|
||||
UINT OnCliprdrServerFormatDataRequest(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_REQUEST* request);
|
||||
UINT OnCliprdrServerFormatDataResponse(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_RESPONSE* response);
|
||||
UINT OnCliprdrServerFileContentsRequest(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* request);
|
||||
UINT OnCliprdrServerFileContentsResponse(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_RESPONSE* response);
|
||||
|
||||
private:
|
||||
using DesktopResizeCallback = BOOL (*)(rdpContext*);
|
||||
using BitmapUpdateCallback = BOOL (*)(rdpContext*, const BITMAP_UPDATE*);
|
||||
using RefreshRectCallback = BOOL (*)(rdpContext*, BYTE, const RECTANGLE_16*);
|
||||
using PointerPositionCallback = BOOL (*)(rdpContext*, const POINTER_POSITION_UPDATE*);
|
||||
using BeginPaintCallback = BOOL (*)(rdpContext*);
|
||||
using EndPaintCallback = BOOL (*)(rdpContext*);
|
||||
using PointerSystemCallback = BOOL (*)(rdpContext*, const POINTER_SYSTEM_UPDATE*);
|
||||
using PointerColorCallback = BOOL (*)(rdpContext*, const POINTER_COLOR_UPDATE*);
|
||||
using PointerNewCallback = BOOL (*)(rdpContext*, const POINTER_NEW_UPDATE*);
|
||||
using PointerCachedCallback = BOOL (*)(rdpContext*, const POINTER_CACHED_UPDATE*);
|
||||
using PointerLargeCallback = BOOL (*)(rdpContext*, const POINTER_LARGE_UPDATE*);
|
||||
using SurfaceBitsCallback = BOOL (*)(rdpContext*, const SURFACE_BITS_COMMAND*);
|
||||
using SurfaceFrameMarkerCallback = BOOL (*)(rdpContext*, const SURFACE_FRAME_MARKER*);
|
||||
using SurfaceFrameBitsCallback = BOOL (*)(rdpContext*, const SURFACE_BITS_COMMAND*, BOOL, BOOL, UINT32);
|
||||
|
||||
struct RenderHooks {
|
||||
BeginPaintCallback begin_paint{};
|
||||
EndPaintCallback end_paint{};
|
||||
DesktopResizeCallback desktop_resize{};
|
||||
BitmapUpdateCallback bitmap_update{};
|
||||
RefreshRectCallback refresh_rect{};
|
||||
SurfaceBitsCallback surface_bits{};
|
||||
SurfaceFrameMarkerCallback surface_frame_marker{};
|
||||
SurfaceFrameBitsCallback surface_frame_bits{};
|
||||
PointerPositionCallback pointer_position{};
|
||||
PointerSystemCallback pointer_system{};
|
||||
PointerColorCallback pointer_color{};
|
||||
PointerNewCallback pointer_new{};
|
||||
PointerCachedCallback pointer_cached{};
|
||||
PointerLargeCallback pointer_large{};
|
||||
};
|
||||
|
||||
struct DirtyRegion {
|
||||
int x{};
|
||||
int y{};
|
||||
int width{};
|
||||
int height{};
|
||||
int rectangles{};
|
||||
};
|
||||
|
||||
struct CallbackPerfStats {
|
||||
std::uint64_t begin_paint{};
|
||||
std::uint64_t end_paint{};
|
||||
std::uint64_t desktop_resize{};
|
||||
std::uint64_t bitmap_update{};
|
||||
std::uint64_t refresh_rect{};
|
||||
std::uint64_t surface_bits{};
|
||||
std::uint64_t surface_frame_marker{};
|
||||
std::uint64_t surface_frame_bits{};
|
||||
std::uint64_t pointer_position{};
|
||||
std::uint64_t pointer_system{};
|
||||
std::uint64_t pointer_color{};
|
||||
std::uint64_t pointer_new{};
|
||||
std::uint64_t pointer_cached{};
|
||||
std::uint64_t pointer_large{};
|
||||
std::uint64_t frame_capture_full{};
|
||||
std::uint64_t frame_capture_region{};
|
||||
std::uint64_t periodic_polls{};
|
||||
std::uint64_t periodic_changes{};
|
||||
std::uint64_t periodic_no_changes{};
|
||||
std::uint64_t interactive_refresh_requests{};
|
||||
std::uint64_t bitmap_update_deferred{};
|
||||
std::uint64_t paint_flush_region{};
|
||||
std::uint64_t paint_flush_full{};
|
||||
std::uint64_t end_paint_change_fallback{};
|
||||
std::uint64_t end_paint_noop{};
|
||||
std::uint64_t rdpgfx_channel_connected{};
|
||||
std::uint64_t rdpgfx_channel_disconnected{};
|
||||
std::uint64_t rdpgfx_pipeline_init_success{};
|
||||
std::uint64_t rdpgfx_pipeline_init_failed{};
|
||||
std::uint64_t rdpgfx_fallback_to_gdi{};
|
||||
std::uint64_t cursor_updates_enqueued{};
|
||||
std::uint64_t event_pump_drained_checks{};
|
||||
std::uint64_t event_pump_wait_timeouts{};
|
||||
std::chrono::steady_clock::time_point first_callback_at{};
|
||||
std::chrono::steady_clock::time_point last_callback_at{};
|
||||
std::chrono::steady_clock::time_point last_summary_at{};
|
||||
std::string last_callback_name;
|
||||
};
|
||||
|
||||
bool ConfigureSettings(const runtime::ConnectionSpec& spec);
|
||||
void ConfigureQualityProfile(const runtime::ConnectionSpec& spec);
|
||||
bool ConfigureRestrictedDrive(const runtime::ConnectionSpec& spec);
|
||||
bool LoadClipboardChannel();
|
||||
bool SubscribeChannelEvents();
|
||||
void UnsubscribeChannelEvents();
|
||||
bool ConfigureClipboardChannel();
|
||||
bool SendClientClipboardCapabilities();
|
||||
bool SendClientClipboardFormatList();
|
||||
bool SendClientClipboardFormatListResponse(bool ok);
|
||||
bool SendClientClipboardDataRequest(UINT32 format_id);
|
||||
bool SendClientClipboardDataResponse(UINT32 format_id);
|
||||
void EnqueueClipboardText(std::string text, std::string origin);
|
||||
std::optional<runtime::RenderNotification> CaptureFrameNotification(
|
||||
const std::string& state,
|
||||
const std::optional<DirtyRegion>& dirty_region = std::nullopt,
|
||||
const std::string& capture_source = "explicit");
|
||||
std::optional<runtime::RenderNotification> CaptureChangedFrameNotification(
|
||||
const std::string& state,
|
||||
const std::string& detection_source = "periodic_change_detector");
|
||||
bool EnsureInputReady() const;
|
||||
uint16_t ScaleCoordinate(double normalized, int size) const;
|
||||
void RequestInteractiveFrameRefresh();
|
||||
void TryEnqueueInteractiveFrameCapture(const char* reason);
|
||||
std::optional<std::pair<std::string, std::int64_t>> RecentInputTraceDelay() const;
|
||||
void AccumulatePendingPaintRegion(const std::optional<DirtyRegion>& dirty_region, int rectangle_count);
|
||||
void ClearPendingPaintCycle();
|
||||
bool SyncPollSnapshotFromCapture(const std::vector<std::uint8_t>& frame_bytes,
|
||||
int frame_width,
|
||||
int frame_height,
|
||||
int frame_stride,
|
||||
const std::optional<DirtyRegion>& dirty_region,
|
||||
bool is_region);
|
||||
void MaybeLogMouseMoveRate();
|
||||
void RecordRdpCallback(const std::string& callback_name);
|
||||
void RecordFrameCapture(bool region);
|
||||
void RecordPeriodicPoll(bool changed);
|
||||
void MaybeLogPeriodicNoChange(const std::string& detection_source,
|
||||
std::chrono::steady_clock::time_point poll_started,
|
||||
std::chrono::steady_clock::time_point poll_completed);
|
||||
void MaybeLogCallbackSummary(const std::string& trigger);
|
||||
void MaybeLogFirstInputCallback(const std::string& callback_name, std::chrono::steady_clock::time_point callback_at);
|
||||
void LogRdpgfxFallbackIfNeeded(const std::string& reason);
|
||||
void LogSurfaceBitsEvent(const std::string& callback_name, const SURFACE_BITS_COMMAND* surface_bits) const;
|
||||
void EnqueueCursorUpdate(const cursor::CursorUpdate& update);
|
||||
void MaybeLogCursorRate(const cursor::CursorUpdate& update);
|
||||
void Cleanup();
|
||||
|
||||
std::shared_ptr<common::Logger> logger_;
|
||||
freerdp* instance_;
|
||||
std::atomic<bool> connected_;
|
||||
int desktop_width_;
|
||||
int desktop_height_;
|
||||
std::string render_quality_profile_;
|
||||
RenderHooks render_hooks_;
|
||||
mutable std::mutex render_mutex_;
|
||||
std::queue<runtime::RenderNotification> render_notifications_;
|
||||
std::queue<runtime::ClipboardNotification> clipboard_notifications_;
|
||||
cursor::CursorAdapter cursor_adapter_;
|
||||
CliprdrClientContext* cliprdr_context_{nullptr};
|
||||
RdpgfxClientContext* rdpgfx_context_{nullptr};
|
||||
bool rdpgfx_enabled_{false};
|
||||
bool channel_events_subscribed_{false};
|
||||
bool rdpgfx_pipeline_active_{false};
|
||||
bool rdpgfx_channel_seen_{false};
|
||||
bool rdpgfx_fallback_logged_{false};
|
||||
std::string client_clipboard_text_;
|
||||
std::string last_client_clipboard_hash_;
|
||||
UINT32 requested_server_clipboard_format_{0};
|
||||
std::uint64_t clipboard_sequence_{0};
|
||||
int cursor_x_{0};
|
||||
int cursor_y_{0};
|
||||
bool cursor_visible_{true};
|
||||
std::uint64_t cursor_sequence_{0};
|
||||
std::chrono::steady_clock::time_point last_cursor_rate_log_at_{};
|
||||
std::uint64_t cursor_updates_since_log_{0};
|
||||
int64_t frame_sequence_{0};
|
||||
std::atomic<bool> interactive_frame_refresh_requested_{false};
|
||||
std::atomic<std::uint32_t> interactive_frame_refresh_budget_{0};
|
||||
std::chrono::steady_clock::time_point last_interactive_frame_capture_at_{};
|
||||
std::chrono::steady_clock::time_point last_mouse_move_refresh_request_at_{};
|
||||
std::chrono::steady_clock::time_point post_input_capture_until_{};
|
||||
std::chrono::steady_clock::time_point next_post_input_capture_at_{};
|
||||
std::chrono::steady_clock::time_point last_mouse_move_rate_log_at_{};
|
||||
std::uint64_t mouse_moves_sent_since_log_{0};
|
||||
std::vector<std::uint8_t> last_polled_frame_;
|
||||
int last_polled_frame_width_{0};
|
||||
int last_polled_frame_height_{0};
|
||||
int last_polled_frame_stride_{0};
|
||||
std::chrono::steady_clock::time_point last_periodic_frame_poll_at_{};
|
||||
std::chrono::steady_clock::time_point last_periodic_no_change_log_at_{};
|
||||
std::uint64_t periodic_no_change_suppressed_since_log_{0};
|
||||
bool paint_cycle_active_{false};
|
||||
bool pending_paint_has_bitmap_update_{false};
|
||||
bool pending_paint_force_full_frame_{false};
|
||||
std::optional<DirtyRegion> pending_paint_dirty_region_;
|
||||
int pending_paint_dirty_rectangles_{0};
|
||||
std::uint64_t pending_paint_bitmap_updates_{0};
|
||||
mutable std::mutex input_trace_mutex_;
|
||||
std::string last_input_trace_correlation_id_;
|
||||
std::chrono::steady_clock::time_point last_input_trace_at_{};
|
||||
bool last_input_waiting_for_first_callback_{false};
|
||||
CallbackPerfStats callback_perf_;
|
||||
};
|
||||
|
||||
} // namespace rdp_worker::freerdp_runtime
|
||||
Reference in New Issue
Block a user