2025-10-19 13:42:29 +02:00
|
|
|
use crate::{
|
|
|
|
|
nodes::{AudioError, MultiSubscriberNode},
|
|
|
|
|
AudioChunk,
|
|
|
|
|
};
|
2025-10-11 00:33:13 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use tokio::sync::mpsc;
|
|
|
|
|
|
|
|
|
|
/// DecoderNode - Décode des chunks audio
|
|
|
|
|
///
|
|
|
|
|
/// Version mock qui passe simplement les chunks (ou simule un décodage simple)
|
|
|
|
|
pub struct DecoderNode {
|
|
|
|
|
rx: mpsc::Receiver<Arc<AudioChunk>>,
|
|
|
|
|
subscribers: MultiSubscriberNode,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DecoderNode {
|
|
|
|
|
pub fn new(channel_size: usize) -> (Self, mpsc::Sender<Arc<AudioChunk>>) {
|
|
|
|
|
let (tx, rx) = mpsc::channel(channel_size);
|
|
|
|
|
|
|
|
|
|
let node = Self {
|
|
|
|
|
rx,
|
|
|
|
|
subscribers: MultiSubscriberNode::new(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
(node, tx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_subscriber(&mut self, tx: mpsc::Sender<Arc<AudioChunk>>) {
|
|
|
|
|
self.subscribers.add_subscriber(tx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Mode passthrough - passe les chunks sans modification
|
|
|
|
|
pub async fn run_passthrough(mut self) -> Result<(), AudioError> {
|
|
|
|
|
while let Some(chunk) = self.rx.recv().await {
|
|
|
|
|
self.subscribers.push(chunk).await?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Mode mock décodage - simule un changement de sample rate
|
|
|
|
|
pub async fn run_with_resampling(mut self, target_sample_rate: u32) -> Result<(), AudioError> {
|
|
|
|
|
while let Some(chunk) = self.rx.recv().await {
|
2025-10-28 18:41:34 +01:00
|
|
|
if chunk.sample_rate() == target_sample_rate {
|
2025-10-11 00:33:13 +02:00
|
|
|
// Pas besoin de resampling
|
|
|
|
|
self.subscribers.push(chunk).await?;
|
|
|
|
|
} else {
|
|
|
|
|
// Simuler un resampling (mock simple)
|
2025-10-28 18:41:34 +01:00
|
|
|
let ratio = target_sample_rate as f64 / chunk.sample_rate() as f64;
|
2025-10-11 00:33:13 +02:00
|
|
|
let new_len = (chunk.len() as f64 * ratio) as usize;
|
|
|
|
|
|
2025-10-28 18:41:34 +01:00
|
|
|
let pairs = chunk.to_pairs_f32();
|
|
|
|
|
let mut resampled = Vec::with_capacity(new_len);
|
2025-10-11 00:33:13 +02:00
|
|
|
|
|
|
|
|
// Resampling linéaire simple (mock)
|
|
|
|
|
for i in 0..new_len {
|
|
|
|
|
let src_pos = i as f64 / ratio;
|
|
|
|
|
let src_idx = src_pos as usize;
|
|
|
|
|
|
2025-10-28 18:41:34 +01:00
|
|
|
if src_idx + 1 < pairs.len() {
|
2025-10-11 00:33:13 +02:00
|
|
|
let frac = src_pos - src_idx as f64;
|
2025-10-28 18:41:34 +01:00
|
|
|
let alpha = (1.0 - frac) as f32;
|
|
|
|
|
let beta = frac as f32;
|
|
|
|
|
let left_sample = pairs[src_idx][0] * alpha + pairs[src_idx + 1][0] * beta;
|
|
|
|
|
let right_sample = pairs[src_idx][1] * alpha + pairs[src_idx + 1][1] * beta;
|
|
|
|
|
|
|
|
|
|
resampled.push([left_sample, right_sample]);
|
|
|
|
|
} else if src_idx < pairs.len() {
|
|
|
|
|
resampled.push(pairs[src_idx]);
|
2025-10-11 00:33:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-28 18:41:34 +01:00
|
|
|
let mut new_chunk = AudioChunk::from_pairs_f32(
|
|
|
|
|
chunk.order(),
|
|
|
|
|
resampled,
|
|
|
|
|
target_sample_rate,
|
|
|
|
|
chunk.bit_depth(),
|
|
|
|
|
);
|
|
|
|
|
if chunk.gain_db().abs() > f64::EPSILON {
|
|
|
|
|
new_chunk = new_chunk.set_gain_db(chunk.gain_db());
|
|
|
|
|
}
|
|
|
|
|
self.subscribers.push(new_chunk).await?;
|
2025-10-11 00:33:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2025-10-28 18:41:34 +01:00
|
|
|
use crate::BitDepth;
|
2025-10-11 00:33:13 +02:00
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_decoder_passthrough() {
|
|
|
|
|
let (mut node, tx) = DecoderNode::new(10);
|
|
|
|
|
let (out_tx, mut out_rx) = mpsc::channel(10);
|
|
|
|
|
|
|
|
|
|
node.add_subscriber(out_tx);
|
|
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
node.run_passthrough().await.unwrap();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Envoyer un chunk
|
2025-10-28 18:41:34 +01:00
|
|
|
let chunk = AudioChunk::from_channels_f32(
|
|
|
|
|
0,
|
|
|
|
|
vec![1.0, 2.0, 3.0],
|
|
|
|
|
vec![4.0, 5.0, 6.0],
|
|
|
|
|
48000,
|
|
|
|
|
BitDepth::B24,
|
|
|
|
|
);
|
|
|
|
|
tx.send(chunk.clone()).await.unwrap();
|
2025-10-11 00:33:13 +02:00
|
|
|
|
|
|
|
|
// Recevoir le chunk
|
|
|
|
|
let received = out_rx.recv().await.unwrap();
|
2025-10-28 18:41:34 +01:00
|
|
|
assert!(Arc::ptr_eq(&chunk, &received));
|
2025-10-11 00:33:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_decoder_resampling() {
|
|
|
|
|
let (mut node, tx) = DecoderNode::new(10);
|
|
|
|
|
let (out_tx, mut out_rx) = mpsc::channel(10);
|
|
|
|
|
|
|
|
|
|
node.add_subscriber(out_tx);
|
|
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
node.run_with_resampling(96000).await.unwrap();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Envoyer un chunk à 48000 Hz
|
2025-10-28 18:41:34 +01:00
|
|
|
let chunk =
|
|
|
|
|
AudioChunk::from_channels_f32(0, vec![1.0; 100], vec![1.0; 100], 48000, BitDepth::B24);
|
|
|
|
|
tx.send(chunk).await.unwrap();
|
2025-10-11 00:33:13 +02:00
|
|
|
|
|
|
|
|
// Recevoir le chunk resampleé
|
|
|
|
|
let received = out_rx.recv().await.unwrap();
|
2025-10-28 18:41:34 +01:00
|
|
|
assert_eq!(received.sample_rate(), 96000);
|
2025-10-11 00:33:13 +02:00
|
|
|
// Le chunk devrait être environ 2x plus grand
|
|
|
|
|
assert!(received.len() > 150 && received.len() < 250);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_decoder_no_resampling_needed() {
|
|
|
|
|
let (mut node, tx) = DecoderNode::new(10);
|
|
|
|
|
let (out_tx, mut out_rx) = mpsc::channel(10);
|
|
|
|
|
|
|
|
|
|
node.add_subscriber(out_tx);
|
|
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
node.run_with_resampling(48000).await.unwrap();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Envoyer un chunk déjà au bon sample rate
|
2025-10-28 18:41:34 +01:00
|
|
|
let chunk =
|
|
|
|
|
AudioChunk::from_channels_f32(0, vec![1.0; 100], vec![1.0; 100], 48000, BitDepth::B24);
|
|
|
|
|
tx.send(chunk.clone()).await.unwrap();
|
2025-10-11 00:33:13 +02:00
|
|
|
|
|
|
|
|
// Le chunk devrait être passé sans modification
|
|
|
|
|
let received = out_rx.recv().await.unwrap();
|
2025-10-28 18:41:34 +01:00
|
|
|
assert!(Arc::ptr_eq(&chunk, &received));
|
2025-10-11 00:33:13 +02:00
|
|
|
}
|
|
|
|
|
}
|