use dahua_camera_rtsp::Camera;
use dahua_camera_core::CameraStatus;
use serde::Serialize;
use std::sync::atomic::Ordering;
#[derive(Debug, Clone, Serialize)]
pub struct CameraView {
pub id: String,
pub label: String,
pub status: CameraStatus,
pub viewers: usize,
pub frames: u64,
pub idr_frames: u64,
pub bytes: u64,
pub reconnects: u64,
pub lagged_drops: u64,
pub decoded_frames: u64,
pub width: Option<u16>,
pub height: Option<u16>,
}
impl CameraView {
pub fn of(camera: &Camera) -> Self {
let params = camera.params();
let stats = camera.stats();
Self {
id: camera.id().to_owned(),
label: camera.config().display_name().to_owned(),
status: camera.status(),
viewers: camera.viewer_count(),
frames: stats.frames.load(Ordering::Relaxed),
idr_frames: stats.idr_frames.load(Ordering::Relaxed),
bytes: stats.bytes.load(Ordering::Relaxed),
reconnects: stats.reconnects.load(Ordering::Relaxed),
lagged_drops: stats.lagged_drops.load(Ordering::Relaxed),
decoded_frames: stats.decoded_frames.load(Ordering::Relaxed),
width: params.as_ref().map(|p| p.codec.width),
height: params.as_ref().map(|p| p.codec.height),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn status_serialises_as_a_tagged_object() {
let json = serde_json::to_value(CameraStatus::Streaming { width: 704, height: 576 })
.expect("serialises");
assert_eq!(json["state"], "streaming");
assert_eq!(json["width"], 704);
}
#[test]
fn idle_status_carries_no_extra_fields() {
let json = serde_json::to_value(CameraStatus::Idle).expect("serialises");
assert_eq!(json["state"], "idle");
assert_eq!(json.as_object().expect("object").len(), 1);
}
#[test]
fn reconnecting_status_reports_the_delay_and_reason() {
let json = serde_json::to_value(CameraStatus::Reconnecting {
after_secs: 4,
reason: "stream ended".into(),
})
.expect("serialises");
assert_eq!(json["state"], "reconnecting");
assert_eq!(json["after_secs"], 4);
assert_eq!(json["reason"], "stream ended");
}
}