Files
One-KVM/src/video/capture_status.rs
mofeng-git 12a3f1c947 feat: 增加设备丢失自恢复机制
增加音频设备丢失自恢复机制,完善视频设备丢失自恢复机制

降级部分日志级别,GOSTC key打印脱敏

代码格式化
2026-05-02 10:55:05 +08:00

76 lines
2.3 KiB
Rust

//! Shared capture status and error classification helpers.
use std::io;
use crate::video::SignalStatus;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CaptureIoErrorKind {
DeviceLost,
TransientSignal { status: Option<SignalStatus> },
Other,
}
pub fn signal_status_from_capture_kind(kind: &str) -> SignalStatus {
SignalStatus::from_str(kind).unwrap_or(SignalStatus::NoSignal)
}
pub fn classify_capture_io_error(err: &io::Error) -> CaptureIoErrorKind {
match err.raw_os_error() {
// ENXIO / ENODEV / ESHUTDOWN: the device node or endpoint is gone.
Some(6) | Some(19) | Some(108) => CaptureIoErrorKind::DeviceLost,
// EIO / EPIPE: source or transport glitched; EPROTO is common for UVC USB.
Some(5) | Some(32) => CaptureIoErrorKind::TransientSignal { status: None },
Some(71) => CaptureIoErrorKind::TransientSignal {
status: Some(SignalStatus::UvcUsbError),
},
_ => CaptureIoErrorKind::Other,
}
}
pub fn is_device_lost_message(message: &str) -> bool {
message.contains("No such file or directory")
|| message.contains("No such device")
|| message.contains("os error 2")
|| message.contains("ENODEV")
|| message.contains("ENXIO")
|| message.contains("ESHUTDOWN")
}
pub fn capture_error_log_key(err: &io::Error) -> String {
let message = err.to_string();
if message.contains("dqbuf failed") && message.contains("EINVAL") {
"capture_dqbuf_einval".to_string()
} else if message.contains("dqbuf failed") {
"capture_dqbuf".to_string()
} else {
format!("capture_{:?}", err.kind())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn maps_known_signal_status_strings() {
assert_eq!(
signal_status_from_capture_kind("out_of_range"),
SignalStatus::OutOfRange
);
assert_eq!(
signal_status_from_capture_kind("unknown"),
SignalStatus::NoSignal
);
}
#[test]
fn classifies_source_change_log_keys() {
let err = io::Error::other("dqbuf failed: EINVAL");
assert_eq!(capture_error_log_key(&err), "capture_dqbuf_einval");
let err = io::Error::new(io::ErrorKind::TimedOut, "capture timeout");
assert_eq!(capture_error_log_key(&err), "capture_TimedOut");
}
}