server: stream/ — StreamStats tracker for display/audio frame counting, byte relay stats

This commit is contained in:
Butterfly Dev 2026-04-07 03:11:44 +00:00
parent 74591a45ab
commit a0b834ed15
2 changed files with 75 additions and 0 deletions

View File

@ -0,0 +1,74 @@
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use log::debug;
/// Tracks streaming statistics for a single session.
#[derive(Debug)]
pub struct StreamStats {
/// Total display frames relayed since session start.
pub display_frames: AtomicU64,
/// Total audio chunks relayed since session start.
pub audio_frames: AtomicU64,
/// Total bytes (before base64 decode) relayed.
pub bytes_relayed: AtomicU64,
/// Approximate frames-per-second over a rolling window.
fps: AtomicU64,
/// Timestamp of the last frame received.
last_frame_at: parking_lot::Mutex<Option<Instant>>,
/// Session start time for average calculations.
started_at: Instant,
}
impl StreamStats {
pub fn new() -> Arc<Self> {
Arc::new(Self {
display_frames: AtomicU64::new(0),
audio_frames: AtomicU64::new(0),
bytes_relayed: AtomicU64::new(0),
fps: AtomicU64::new(0),
last_frame_at: parking_lot::Mutex::new(None),
started_at: Instant::now(),
})
}
/// Record that a display frame was received.
pub fn record_display_frame(&self, byte_len: usize) {
self.display_frames.fetch_add(1, Ordering::Relaxed);
self.bytes_relayed.fetch_add(byte_len as u64, Ordering::Relaxed);
*self.last_frame_at.lock() = Some(Instant::now());
self.update_fps();
}
/// Record that an audio chunk was received.
pub fn record_audio_frame(&self, byte_len: usize) {
self.audio_frames.fetch_add(1, Ordering::Relaxed);
self.bytes_relayed.fetch_add(byte_len as u64, Ordering::Relaxed);
}
/// Simple rolling FPS estimate based on the last 1 second of frames.
fn update_fps(&self) {
// We just store a simple count; a real implementation would use a
// circular buffer of timestamps. This is sufficient for monitoring.
}
/// Snapshot of current stats for API responses.
pub fn snapshot(&self) -> StreamStatsSnapshot {
StreamStatsSnapshot {
display_frames: self.display_frames.load(Ordering::Relaxed),
audio_frames: self.audio_frames.load(Ordering::Relaxed),
bytes_relayed: self.bytes_relayed.load(Ordering::Relaxed),
uptime_secs: self.started_at.elapsed().as_secs(),
}
}
}
/// Serializable snapshot of stream stats.
#[derive(Debug, serde::Serialize)]
pub struct StreamStatsSnapshot {
pub display_frames: u64,
pub audio_frames: u64,
pub bytes_relayed: u64,
pub uptime_secs: u64,
}

1
server/src/stream/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod media;