#[cfg(test)]
mod mixer_e2e_tests {
use crate::media::mixer::{AudioMixer, MediaMixer, SupervisorMixerMode};
use crate::media::mixer_input::{DecodedFrame, MixerInput};
use crate::media::mixer_output::MixerOutput;
use crate::proxy::proxy_call::test_util::tests::MockMediaPeer;
use audio_codec::CodecType;
use std::sync::Arc;
#[test]
fn test_encode_mix_decode_pipeline() {
let peer1 = Arc::new(MockMediaPeer::new());
let peer2 = Arc::new(MockMediaPeer::new());
let mut output1 = MixerOutput::new("output-1".to_string(), peer1, CodecType::PCMU);
let mut output2 = MixerOutput::new("output-2".to_string(), peer2, CodecType::PCMU);
let samples1: Vec<i16> = (0..160).map(|i| (i as i16 * 10).min(3000)).collect();
let samples2: Vec<i16> = (0..160).map(|i| (1000 - i as i16 * 5).max(-3000)).collect();
let _encoded1 = output1.encode(&samples1).expect("should encode");
let _encoded2 = output2.encode(&samples2).expect("should encode");
let mixer = AudioMixer::new(8000, 1);
let mixed = mixer.mix_frames(vec![samples1, samples2], &[1.0, 1.0]);
assert_eq!(mixed.len(), 160);
assert!(mixed.iter().all(|&s| (i16::MIN..=i16::MAX).contains(&s)));
}
#[test]
fn test_mixing_with_different_gains() {
let mixer = AudioMixer::new(8000, 1);
let frame1 = vec![1000i16; 160];
let frame2 = vec![1000i16; 160];
let frame3 = vec![1000i16; 160];
let gains = [1.0, 0.5, 0.0];
let result = mixer.mix_frames(vec![frame1, frame2, frame3], &gains);
assert_eq!(result.len(), 160);
assert!(result.iter().all(|&s| (1400..=1600).contains(&s)));
}
#[test]
fn test_supervisor_mode_listen_routing() {
let mixer = MediaMixer::new("test-supervisor".to_string(), 8000);
mixer.set_mode(SupervisorMixerMode::Listen);
mixer.apply_supervisor_mode(
"customer",
"agent",
"supervisor",
"customer-out",
"agent-out",
"supervisor-out",
);
let routes = mixer.get_routes();
let customer_route = routes.get("customer").expect("customer route exists");
assert!(
customer_route.outputs.contains_key("supervisor-out"),
"customer should route to supervisor-out in Listen mode"
);
let agent_route = routes.get("agent").expect("agent route exists");
assert!(
agent_route.outputs.contains_key("supervisor-out"),
"agent should route to supervisor-out in Listen mode"
);
let supervisor_route = routes.get("supervisor").expect("supervisor route exists");
assert!(
supervisor_route.outputs.is_empty(),
"supervisor should not send in Listen mode"
);
}
#[test]
fn test_supervisor_mode_whisper_routing() {
let mixer = MediaMixer::new("test-supervisor".to_string(), 8000);
mixer.set_mode(SupervisorMixerMode::Whisper);
mixer.apply_supervisor_mode(
"customer",
"agent",
"supervisor",
"customer-out",
"agent-out",
"supervisor-out",
);
let routes = mixer.get_routes();
let customer_route = routes.get("customer").expect("customer route exists");
assert!(customer_route.outputs.contains_key("agent-out"));
assert!(customer_route.outputs.contains_key("supervisor-out"));
let agent_route = routes.get("agent").expect("agent route exists");
assert!(agent_route.outputs.contains_key("customer-out"));
assert!(agent_route.outputs.contains_key("supervisor-out"));
let supervisor_route = routes.get("supervisor").expect("supervisor route exists");
assert!(supervisor_route.outputs.contains_key("agent-out"));
assert!(!supervisor_route.outputs.contains_key("customer-out"));
}
#[test]
fn test_supervisor_mode_barge_routing() {
let mixer = MediaMixer::new("test-supervisor".to_string(), 8000);
mixer.set_mode(SupervisorMixerMode::Barge);
mixer.apply_supervisor_mode(
"customer",
"agent",
"supervisor",
"customer-out",
"agent-out",
"supervisor-out",
);
let routes = mixer.get_routes();
let customer_route = routes.get("customer").expect("customer route exists");
assert!(customer_route.outputs.contains_key("agent-out"));
assert!(customer_route.outputs.contains_key("supervisor-out"));
let agent_route = routes.get("agent").expect("agent route exists");
assert!(agent_route.outputs.contains_key("customer-out"));
assert!(agent_route.outputs.contains_key("supervisor-out"));
let supervisor_route = routes.get("supervisor").expect("supervisor route exists");
assert!(supervisor_route.outputs.contains_key("customer-out"));
assert!(supervisor_route.outputs.contains_key("agent-out"));
}
#[test]
fn test_output_routing_configuration() {
let mixer = MediaMixer::new("test-routing".to_string(), 8000);
mixer.set_output_routing(
"agent-out",
vec!["customer".to_string(), "supervisor".to_string()],
);
mixer.set_output_routing("customer-out", vec!["agent".to_string()]);
let agent_routing = mixer.get_output_routing("agent-out").unwrap();
assert_eq!(agent_routing, vec!["customer", "supervisor"]);
let customer_routing = mixer.get_output_routing("customer-out").unwrap();
assert_eq!(customer_routing, vec!["agent"]);
}
#[test]
fn test_decoded_frame_lifecycle() {
let frame =
DecodedFrame::new("input-1".to_string(), vec![100i16; 160], 8000, 0).with_sequence(42);
assert_eq!(frame.input_id, "input-1");
assert_eq!(frame.samples.len(), 160);
assert_eq!(frame.sample_rate, 8000);
assert_eq!(frame.timestamp, 0);
assert_eq!(frame.sequence, Some(42));
}
#[test]
fn test_mixer_saturation_at_boundary() {
let mixer = AudioMixer::new(8000, 1);
let frame1 = vec![i16::MAX; 160];
let frame2 = vec![i16::MAX; 160];
let frame3 = vec![i16::MAX; 160];
let result = mixer.mix_frames(vec![frame1, frame2, frame3], &[1.0, 1.0, 1.0]);
assert!(result.iter().all(|&s| s == i16::MAX));
}
#[test]
fn test_mixer_negative_samples() {
let mixer = AudioMixer::new(8000, 1);
let frame1 = vec![-1000i16; 160];
let frame2 = vec![-500i16; 160];
let result = mixer.mix_frames(vec![frame1, frame2], &[1.0, 1.0]);
assert!(result.iter().all(|&s| s < -1400 && s > -1600));
}
#[test]
fn test_gain_application_in_mixer() {
let mixer = AudioMixer::new(8000, 1);
let frame = vec![1000i16; 160];
let result = mixer.mix_frames(vec![frame.clone()], &[2.0]);
assert!(result.iter().all(|&s| (1900..=2100).contains(&s)));
let result = mixer.mix_frames(vec![frame], &[0.5]);
assert!(result.iter().all(|&s| (450..=550).contains(&s)));
}
#[test]
fn test_codec_compatibility_pcmu() {
let peer = Arc::new(MockMediaPeer::new());
let input = MixerInput::new("input-1".to_string(), peer.clone(), CodecType::PCMU);
let mut output = MixerOutput::new("output-1".to_string(), peer, CodecType::PCMU);
assert_eq!(input.codec(), CodecType::PCMU);
assert_eq!(output.codec(), CodecType::PCMU);
let samples: Vec<i16> = (0..160).map(|i| i as i16).collect();
let encoded = output.encode(&samples);
assert!(encoded.is_some());
}
#[tokio::test]
async fn test_mixer_start_stop_lifecycle() {
let mixer = MediaMixer::new("test-lifecycle".to_string(), 8000);
mixer.start();
mixer.stop();
mixer.start();
mixer.stop();
}
}