#[cfg(test)]
mod tests {
use crate::media::{
AudioFrame, Samples,
recorder::{Recorder, RecorderOption},
};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tempfile::tempdir;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
async fn run_rtp_forwarding(
total_packets: usize,
payload: Vec<u8>,
recorder_tx: Option<mpsc::UnboundedSender<AudioFrame>>,
) -> Duration {
let start = Instant::now();
for i in 0..total_packets {
let frame = AudioFrame {
track_id: "track_1".to_string(),
samples: Samples::RTP {
sequence_number: i as u16,
payload_type: 0, payload: payload.clone(),
},
timestamp: (i * 160) as u64,
sample_rate: 8000,
channels: 1,
..Default::default()
};
let _forwarded_frame = frame.clone();
if let Some(tx) = &recorder_tx {
tx.send(frame).ok();
}
}
start.elapsed()
}
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
async fn run_buffered_write_simulation(total_packets: usize, payload: Vec<u8>) -> Duration {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("bench_buffered.wav");
let file = File::create(file_path).unwrap();
let mut writer = BufWriter::new(file);
let start = Instant::now();
for _ in 0..total_packets {
writer.write_all(&payload).unwrap();
}
writer.flush().unwrap();
start.elapsed()
}
#[tokio::test]
async fn test_rtp_forwarding_overhead() {
let duration_sec = 60;
let packet_ms = 20;
let total_packets = (duration_sec * 1000) / packet_ms;
let payload = vec![0u8; 160];
println!(
"Benchmark: RTP Forwarding ({}s, {} packets)",
duration_sec, total_packets
);
let duration_no_rec = run_rtp_forwarding(total_packets, payload.clone(), None).await;
println!("Without Recording: {:?}", duration_no_rec);
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("bench_rtp.wav");
let cancel_token = CancellationToken::new();
let config = RecorderOption::default();
let recorder = Arc::new(Recorder::new(
cancel_token.clone(),
"bench_rtp".to_string(),
config,
));
let (tx, rx) = mpsc::unbounded_channel();
let recorder_clone = recorder.clone();
let file_path_clone = file_path.clone();
let record_handle =
tokio::spawn(
async move { recorder_clone.process_recording(&file_path_clone, rx).await },
);
let duration_with_rec = run_rtp_forwarding(total_packets, payload.clone(), Some(tx)).await;
println!("With Recording (Async): {:?}", duration_with_rec);
record_handle.await.unwrap().unwrap();
let duration_buffered = run_buffered_write_simulation(total_packets, payload.clone()).await;
println!("Buffered Write (Sync): {:?}", duration_buffered);
let overhead = if duration_with_rec > duration_no_rec {
duration_with_rec - duration_no_rec
} else {
Duration::from_secs(0)
};
println!("Async Recording Overhead: {:?}", overhead);
println!(
"Overhead per packet: {:?}",
overhead / total_packets as u32
);
let metadata = std::fs::metadata(&file_path).unwrap();
let expected_size = 44 + (total_packets * 160) as u64;
assert_eq!(
metadata.len(),
expected_size,
"Recording file size mismatch"
);
}
}