use serde::{Deserialize, Serialize}; use std::collections::VecDeque; use std::fmt::Write as _; use crate::uplink_telemetry::UpstreamStreamTelemetry; use super::{ devices::CameraMode, state::{CaptureSizeChoice, FeedSourcePreset, InputRouting, LauncherState, ViewMode}, }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct PerformanceSample { pub rtt_ms: f32, pub probe_spread_ms: f32, pub input_latency_ms: f32, pub probe_loss_pct: f32, pub client_process_cpu_pct: f32, pub server_process_cpu_pct: f32, pub video_loss_pct: f32, pub left_receive_fps: f32, pub left_present_fps: f32, pub left_server_fps: f32, pub left_stream_spread_ms: f32, pub left_packet_gap_peak_ms: f32, pub left_present_gap_peak_ms: f32, pub left_queue_depth: u32, pub left_queue_peak: u32, pub left_server_source_gap_peak_ms: f32, pub left_server_send_gap_peak_ms: f32, pub left_server_queue_peak: u32, pub left_server_encoder_label: String, pub left_decoder_label: String, pub left_stream_caps_label: String, pub left_decoded_caps_label: String, pub left_rendered_caps_label: String, pub right_receive_fps: f32, pub right_present_fps: f32, pub right_server_fps: f32, pub right_stream_spread_ms: f32, pub right_packet_gap_peak_ms: f32, pub right_present_gap_peak_ms: f32, pub right_queue_depth: u32, pub right_queue_peak: u32, pub right_server_source_gap_peak_ms: f32, pub right_server_send_gap_peak_ms: f32, pub right_server_queue_peak: u32, pub right_server_encoder_label: String, pub right_decoder_label: String, pub right_stream_caps_label: String, pub right_decoded_caps_label: String, pub right_rendered_caps_label: String, pub upstream_camera: UpstreamStreamTelemetry, pub upstream_microphone: UpstreamStreamTelemetry, pub dropped_frames: u64, pub queue_depth: u32, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DiagnosticsLog { capacity: usize, history: VecDeque, } impl DiagnosticsLog { pub fn new(capacity: usize) -> Self { let capacity = capacity.max(1); Self { capacity, history: VecDeque::with_capacity(capacity), } } pub fn record(&mut self, sample: PerformanceSample) { if self.history.len() == self.capacity { let _ = self.history.pop_front(); } self.history.push_back(sample); } pub fn latest(&self) -> Option<&PerformanceSample> { self.history.back() } pub fn len(&self) -> usize { self.history.len() } pub fn is_empty(&self) -> bool { self.history.is_empty() } pub fn iter(&self) -> impl Iterator { self.history.iter() } } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct MediaChannelState { pub camera: bool, pub microphone: bool, pub audio: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SnapshotReport { pub client_version: String, pub server_version: Option, pub server_available: bool, pub routing: InputRouting, pub view_mode: ViewMode, pub remote_active: bool, pub power_state: String, pub client_process_cpu_pct: f32, pub server_process_cpu_pct: f32, pub preview_source: String, pub client_display_limit: String, pub left_surface: String, pub left_feed_source: String, pub left_capture_profile: String, pub left_capture_transport: String, pub left_breakout_profile: String, pub left_decoder_label: String, pub left_stream_spread_ms: f32, pub left_packet_gap_peak_ms: f32, pub left_present_gap_peak_ms: f32, pub left_queue_depth: u32, pub left_queue_peak: u32, pub left_server_source_gap_peak_ms: f32, pub left_server_send_gap_peak_ms: f32, pub left_server_queue_peak: u32, pub left_server_encoder_label: String, pub left_stream_caps_label: String, pub left_decoded_caps_label: String, pub left_rendered_caps_label: String, pub right_surface: String, pub right_feed_source: String, pub right_capture_profile: String, pub right_capture_transport: String, pub right_breakout_profile: String, pub right_decoder_label: String, pub right_stream_spread_ms: f32, pub right_packet_gap_peak_ms: f32, pub right_present_gap_peak_ms: f32, pub right_queue_depth: u32, pub right_queue_peak: u32, pub right_server_source_gap_peak_ms: f32, pub right_server_send_gap_peak_ms: f32, pub right_server_queue_peak: u32, pub right_server_encoder_label: String, pub right_stream_caps_label: String, pub right_decoded_caps_label: String, pub right_rendered_caps_label: String, pub selected_camera: Option, pub camera_quality_label: String, pub selected_microphone: Option, pub selected_speaker: Option, pub media_channels: MediaChannelState, pub audio_gain_label: String, pub mic_gain_label: String, pub upstream_camera: UpstreamStreamTelemetry, pub upstream_microphone: UpstreamStreamTelemetry, pub av_delivery_skew_ms: f32, pub av_enqueue_skew_ms: f32, pub av_sync_health: String, pub calibration_available: bool, pub calibration_profile: String, pub calibration_source: String, pub calibration_confidence: String, pub calibration_detail: String, pub calibration_updated_at: String, pub factory_audio_offset_us: i64, pub factory_video_offset_us: i64, pub default_audio_offset_us: i64, pub default_video_offset_us: i64, pub active_audio_offset_us: i64, pub active_video_offset_us: i64, pub selected_keyboard: Option, pub selected_mouse: Option, pub status: String, pub recent_samples: Vec, pub notes: Vec, pub recommendations: Vec, pub probe_command: String, }