#[cfg(not(coverage))] fn audio_usb_auto_recover_enabled() -> bool { std::env::var("LESAVKA_AUDIO_AUTO_RECOVER_USB") .map(|raw| { !matches!( raw.trim().to_ascii_lowercase().as_str(), "0" | "false" | "no" | "off" ) }) .unwrap_or(false) } #[cfg(not(coverage))] fn audio_usb_recover_after() -> u32 { std::env::var("LESAVKA_AUDIO_AUTO_RECOVER_AFTER") .ok() .and_then(|raw| raw.parse::().ok()) .filter(|value| *value > 0) .unwrap_or(3) } #[cfg(not(coverage))] fn audio_usb_recover_cooldown() -> Duration { let millis = std::env::var("LESAVKA_AUDIO_AUTO_RECOVER_COOLDOWN_MS") .ok() .and_then(|raw| raw.parse::().ok()) .unwrap_or(60_000); Duration::from_millis(millis) } #[cfg(not(coverage))] fn is_recoverable_remote_audio_error(message: &str) -> bool { message.contains("remote speaker capture produced no audio samples") || message.contains("remote speaker capture stalled") || message.contains("remote speaker capture cadence is too low") } #[cfg(not(coverage))] #[derive(Debug, Default)] struct AudioFailureLogLimiter { last_warn_at: Option, suppressed_repeats: u64, last_message: String, } #[cfg(not(coverage))] /// Rate-limit repeated remote audio failures so operators see state changes, not log floods. impl AudioFailureLogLimiter { /// Emit the first failure promptly, then aggregate identical repeats. fn record(&mut self, context: &'static str, message: &str) { let same_message = self.last_message == message; let should_warn = !same_message || self .last_warn_at .map(|last| last.elapsed() >= AUDIO_FAILURE_WARN_INTERVAL) .unwrap_or(true); if should_warn { tracing::warn!( context, suppressed_repeats = self.suppressed_repeats, "❌🔊 audio stream unhealthy: {message}" ); self.last_warn_at = Some(Instant::now()); self.suppressed_repeats = 0; self.last_message.clear(); self.last_message.push_str(message); } else { self.suppressed_repeats = self.suppressed_repeats.saturating_add(1); tracing::debug!( context, suppressed_repeats = self.suppressed_repeats, "audio stream repeated unhealthy state suppressed from WARN noise: {message}" ); } } } #[cfg(not(coverage))] const AUDIO_FAILURE_WARN_INTERVAL: Duration = Duration::from_secs(30); pub(crate) fn keyboard_stream_report( report: Result, remote_capture_enabled: bool, remote_capture_was_enabled: &mut bool, ) -> Option { if !remote_capture_enabled { let emit_reset = *remote_capture_was_enabled; *remote_capture_was_enabled = false; return emit_reset.then_some(KeyboardReport { data: vec![0; 8] }); } *remote_capture_was_enabled = true; match report { Ok(report) => Some(report), Err(BroadcastStreamRecvError::Lagged(skipped)) => { warn!( skipped, "⌨️ live keyboard stream lagged; sending a clean reset report before continuing" ); Some(KeyboardReport { data: vec![0; 8] }) } } } pub(crate) fn mouse_stream_report( report: Result, remote_capture_enabled: bool, remote_capture_was_enabled: &mut bool, ) -> Option { if !remote_capture_enabled { let emit_reset = *remote_capture_was_enabled; *remote_capture_was_enabled = false; return emit_reset.then_some(MouseReport { data: vec![0; 4] }); } *remote_capture_was_enabled = true; match report { Ok(report) => Some(report), Err(BroadcastStreamRecvError::Lagged(skipped)) => { warn!( skipped, "🖱️ live mouse stream lagged; sending a neutral report before continuing" ); Some(MouseReport { data: vec![0; 4] }) } } }