//! Tests d'intégration pour le pipeline audio complet use pmoaudio::{BufferNode, DecoderNode, DspNode, SinkNode, SourceNode, TimerNode}; #[tokio::test] async fn test_complete_pipeline() { // Créer un pipeline complet : Source → Decoder → DSP → Buffer → Timer → Sink let (mut decoder, decoder_tx) = DecoderNode::new(10); let (mut dsp, dsp_tx) = DspNode::new(10, 0.5); // Gain de 0.5 let (mut buffer, buffer_tx) = BufferNode::new(50, 10); let (mut timer, timer_tx) = TimerNode::new(10); let (sink, sink_tx) = SinkNode::new("Integration Test".to_string(), 10); // Connecter le pipeline decoder.add_subscriber(dsp_tx); dsp.add_subscriber(buffer_tx); buffer.add_next_subscriber(timer_tx); timer.add_subscriber(sink_tx); let timer_handle = timer.get_position_handle(); // Spawn tous les nodes tokio::spawn(async move { decoder.run_passthrough().await.unwrap() }); tokio::spawn(async move { dsp.run().await.unwrap() }); tokio::spawn(async move { buffer.run().await.unwrap() }); tokio::spawn(async move { timer.run().await.unwrap() }); let sink_handle = tokio::spawn(async move { sink.run_with_stats().await.unwrap() }); // Générer des chunks tokio::spawn(async move { let mut source = SourceNode::new(); source.add_subscriber(decoder_tx); source .generate_chunks(10, 4800, 48000, 440.0) .await .unwrap(); }); // Attendre la fin let stats = sink_handle.await.unwrap(); // Vérifier les résultats assert_eq!(stats.chunks_received, 10); assert_eq!(stats.total_samples, 48000); // Vérifier que le gain a été appliqué (peak devrait être ~0.5) assert!(stats.peak_left < 0.51 && stats.peak_left > 0.49); // Vérifier la position let position = timer_handle.position_sec().await; assert!((position - 1.0).abs() < 0.01); // ~1 seconde } #[tokio::test] async fn test_multiroom_buffering() { // Tester le BufferNode avec plusieurs abonnés avec offsets let (buffer, buffer_tx) = BufferNode::new(50, 20); let (sink1, sink1_tx) = SinkNode::new("Room 1".to_string(), 20); let (sink2, sink2_tx) = SinkNode::new("Room 2".to_string(), 20); let (sink3, sink3_tx) = SinkNode::new("Room 3".to_string(), 20); buffer.add_subscriber_with_offset(sink1_tx, 0).await; buffer.add_subscriber_with_offset(sink2_tx, 3).await; buffer.add_subscriber_with_offset(sink3_tx, 6).await; tokio::spawn(async move { buffer.run().await.unwrap() }); let sink1_handle = tokio::spawn(async move { sink1.run_with_stats().await.unwrap() }); let sink2_handle = tokio::spawn(async move { sink2.run_with_stats().await.unwrap() }); let sink3_handle = tokio::spawn(async move { sink3.run_with_stats().await.unwrap() }); tokio::spawn(async move { let mut source = SourceNode::new(); source.add_subscriber(buffer_tx); source .generate_chunks(20, 1000, 48000, 440.0) .await .unwrap(); }); let stats1 = sink1_handle.await.unwrap(); let stats2 = sink2_handle.await.unwrap(); let stats3 = sink3_handle.await.unwrap(); // Room 1 devrait avoir tous les chunks assert_eq!(stats1.chunks_received, 20); // Room 2 devrait avoir 3 chunks de moins assert_eq!(stats2.chunks_received, 17); // Room 3 devrait avoir 6 chunks de moins assert_eq!(stats3.chunks_received, 14); } #[tokio::test] async fn test_timer_accuracy() { // Tester la précision du TimerNode let (mut timer, timer_tx) = TimerNode::new(10); let (sink, sink_tx) = SinkNode::new("Timer Test".to_string(), 10); timer.add_subscriber(sink_tx); let timer_handle = timer.get_position_handle(); tokio::spawn(async move { timer.run().await.unwrap() }); let sink_handle = tokio::spawn(async move { sink.run_silent().await.unwrap() }); tokio::spawn(async move { let mut source = SourceNode::new(); source.add_subscriber(timer_tx); // 48000 samples à 48kHz = 1 seconde source .generate_chunks(1, 48000, 48000, 440.0) .await .unwrap(); }); sink_handle.await.unwrap(); let position = timer_handle.position_sec().await; let samples = timer_handle.elapsed_samples().await; assert_eq!(samples, 48000); assert!((position - 1.0).abs() < 0.0001); } #[tokio::test] async fn test_arc_sharing() { // Vérifier que les chunks sont bien partagés via Arc sans copie let (mut timer, timer_tx) = TimerNode::new(10); let (sink1, sink1_tx) = SinkNode::new("Sink1".to_string(), 10); let (sink2, sink2_tx) = SinkNode::new("Sink2".to_string(), 10); timer.add_subscriber(sink1_tx); timer.add_subscriber(sink2_tx); tokio::spawn(async move { timer.run().await.unwrap() }); let sink1_handle = tokio::spawn(async move { sink1.run_with_stats().await.unwrap() }); let sink2_handle = tokio::spawn(async move { sink2.run_with_stats().await.unwrap() }); tokio::spawn(async move { let mut source = SourceNode::new(); source.add_subscriber(timer_tx); source.generate_silence(5, 1000, 48000).await.unwrap(); }); let stats1 = sink1_handle.await.unwrap(); let stats2 = sink2_handle.await.unwrap(); // Les deux sinks devraient avoir reçu les mêmes chunks assert_eq!(stats1.chunks_received, 5); assert_eq!(stats2.chunks_received, 5); assert_eq!(stats1.total_samples, stats2.total_samples); }