use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
use tracing::debug;
use crate::api::common::error::MediaTransportError;
use crate::api::common::stats::{MediaStats, QualityLevel};
use crate::api::server::transport::core::connection::ClientConnection;
#[derive(Debug, Default, Clone)]
pub struct ServerMetrics {
pub active_clients: usize,
pub total_bytes_received: u64,
pub total_bytes_sent: u64,
pub total_packets_received: u64,
pub total_packets_sent: u64,
pub average_jitter_ms: f32,
pub average_packet_loss: f32,
pub total_downstream_bandwidth_bps: u64,
pub total_upstream_bandwidth_bps: u64,
pub average_rtt_ms: Option<f32>,
pub overall_quality: QualityLevel,
pub total_rtcp_packets_received: u64,
pub total_rtcp_packets_sent: u64,
pub uptime: Duration,
}
pub fn calculate_mos_from_rfactor(r_factor: f32) -> f32 {
if r_factor < 0.0 {
return 1.0;
} else if r_factor > 100.0 {
return 4.5;
}
if r_factor < 0.0 {
1.0
} else if r_factor < 6.52 {
1.0
} else if r_factor < 100.0 {
1.0 + 0.035 * r_factor + 0.000007 * r_factor * (r_factor - 60.0) * (100.0 - r_factor)
} else {
4.5
}
}
pub fn calculate_rfactor(
packet_loss_percent: f32,
jitter_ms: f32,
rtt_ms: f32,
) -> f32 {
let r0 = 93.2;
let is = if packet_loss_percent <= 0.0 {
0.0
} else {
2.0 + 14.0 * (1.0 - (1.0 - packet_loss_percent / 100.0).powf(30.0))
};
let ij = if jitter_ms < 1.0 {
0.0
} else {
0.8 + 0.5 * jitter_ms.sqrt()
};
let id = if rtt_ms < 100.0 {
0.0
} else if rtt_ms < 300.0 {
(rtt_ms - 100.0) / 20.0
} else {
10.0 + (rtt_ms - 300.0) / 10.0
};
let r = r0 - is - id - ij;
r.max(0.0).min(100.0)
}
pub async fn get_server_metrics(
clients: &Arc<RwLock<HashMap<String, ClientConnection>>>,
media_stats: &MediaStats,
server_start_time: Duration,
) -> Result<ServerMetrics, MediaTransportError> {
let clients_guard = clients.read().await;
let mut metrics = ServerMetrics::default();
metrics.active_clients = clients_guard.values().filter(|c| c.connected).count();
let mut total_jitter = 0.0;
let mut total_packet_loss = 0.0;
let mut total_rtt = 0.0;
let mut rtt_count = 0;
for stream in media_stats.streams.values() {
metrics.total_bytes_received += stream.byte_count;
metrics.total_packets_received += stream.packet_count;
total_jitter += stream.jitter_ms;
total_packet_loss += stream.fraction_lost;
if let Some(rtt) = stream.rtt_ms {
total_rtt += rtt;
rtt_count += 1;
}
}
let stream_count = media_stats.streams.len();
if stream_count > 0 {
metrics.average_jitter_ms = total_jitter / stream_count as f32;
metrics.average_packet_loss = total_packet_loss / stream_count as f32 * 100.0; }
if rtt_count > 0 {
metrics.average_rtt_ms = Some(total_rtt / rtt_count as f32);
}
metrics.total_downstream_bandwidth_bps = media_stats.downstream_bandwidth_bps as u64;
metrics.total_upstream_bandwidth_bps = media_stats.upstream_bandwidth_bps as u64;
metrics.overall_quality = media_stats.quality;
metrics.uptime = server_start_time;
Ok(metrics)
}