Ou encore un peu de factorisation dans les nœuds.

This commit is contained in:
2025-11-17 21:43:57 +01:00
parent 9bc0c2544d
commit 9be6835ddc
12 changed files with 194 additions and 159 deletions

View File

@@ -15,7 +15,7 @@
use crate::{
nodes::AudioError,
pipeline::{Node, NodeLogic},
pipeline::{send_to_children, Node, NodeLogic},
AudioChunk, AudioPipelineNode, AudioSegment,
};
use std::sync::Arc;
@@ -100,12 +100,7 @@ where
segment
};
// Envoyer à tous les enfants
for tx in &output {
tx.send(output_segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
send_to_children(std::any::type_name::<Self>(), &output, output_segment).await?;
}
Ok(())

View File

@@ -1,6 +1,6 @@
use crate::{
nodes::{AudioError, TypedAudioNode, DEFAULT_CHUNK_DURATION_MS},
pipeline::{AudioPipelineNode, Node, NodeLogic},
pipeline::{send_to_children, AudioPipelineNode, Node, NodeLogic},
type_constraints::TypeRequirement,
AudioChunk, AudioChunkData, AudioSegment, I24,
};
@@ -47,17 +47,6 @@ impl NodeLogic for FileSourceLogic {
output.len()
);
// Macro helper pour envoyer à tous les enfants
macro_rules! send_to_children {
($segment:expr) => {
for tx in &output {
tx.send($segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
};
}
// Ouvrir le fichier
let file = File::open(&self.path)
.await
@@ -82,7 +71,7 @@ impl NodeLogic for FileSourceLogic {
// Émettre TopZeroSync
let top_zero = AudioSegment::new_top_zero_sync();
send_to_children!(top_zero);
send_to_children(std::any::type_name::<Self>(), &output, top_zero).await?;
// Extraire et émettre les métadonnées du fichier
if let Ok(file_metadata) = AudioFileMetadata::from_file(&self.path) {
@@ -110,7 +99,7 @@ impl NodeLogic for FileSourceLogic {
0.0,
Arc::new(tokio::sync::RwLock::new(metadata)),
);
send_to_children!(track_boundary);
send_to_children(std::any::type_name::<Self>(), &output, track_boundary).await?;
}
// Préparer la lecture des chunks audio
@@ -168,7 +157,7 @@ impl NodeLogic for FileSourceLogic {
timestamp_sec,
)?;
send_to_children!(segment);
send_to_children(std::any::type_name::<Self>(), &output, segment).await?;
chunk_index += 1;
total_frames += frames_to_emit as u64;
@@ -183,7 +172,7 @@ impl NodeLogic for FileSourceLogic {
let timestamp_sec = total_frames as f64 / stream_info.sample_rate as f64;
let segment =
bytes_to_segment(&pending, &stream_info, frames, chunk_index, timestamp_sec)?;
send_to_children!(segment);
send_to_children(std::any::type_name::<Self>(), &output, segment).await?;
total_frames += frames as u64;
chunk_index += 1;
}
@@ -192,7 +181,7 @@ impl NodeLogic for FileSourceLogic {
// Émettre EndOfStream
let final_timestamp = total_frames as f64 / stream_info.sample_rate as f64;
let eos = AudioSegment::new_end_of_stream(chunk_index, final_timestamp);
send_to_children!(eos);
send_to_children(std::any::type_name::<Self>(), &output, eos).await?;
// Attendre la fin du décodage
stream

View File

@@ -1,6 +1,6 @@
use crate::{
nodes::{AudioError, TypedAudioNode, DEFAULT_CHUNK_DURATION_MS},
pipeline::{Node, NodeLogic},
pipeline::{send_to_children, Node, NodeLogic},
type_constraints::TypeRequirement,
AudioChunk, AudioChunkData, AudioPipelineNode, AudioSegment, I24,
};
@@ -127,16 +127,6 @@ impl NodeLogic for HttpSourceLogic {
output: Vec<mpsc::Sender<Arc<AudioSegment>>>,
stop_token: CancellationToken,
) -> Result<(), AudioError> {
macro_rules! send_to_children {
($segment:expr) => {
for tx in &output {
tx.send($segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
};
}
// Effectuer la requête HTTP
let response = reqwest::get(&self.url).await.map_err(|e| {
AudioError::ProcessingError(format!("HTTP request failed for {}: {}", self.url, e))
@@ -179,12 +169,17 @@ impl NodeLogic for HttpSourceLogic {
};
// Émettre TopZeroSync
send_to_children!(AudioSegment::new_top_zero_sync());
send_to_children(
std::any::type_name::<Self>(),
&output,
AudioSegment::new_top_zero_sync(),
)
.await?;
// Émettre TrackBoundary avec les métadonnées HTTP
let track_boundary =
AudioSegment::new_track_boundary(0, 0.0, Arc::new(tokio::sync::RwLock::new(metadata)));
send_to_children!(track_boundary);
send_to_children(std::any::type_name::<Self>(), &output, track_boundary).await?;
// Préparer la lecture des chunks audio
let frame_bytes = stream_info.bytes_per_sample() * stream_info.channels as usize;
@@ -242,7 +237,7 @@ impl NodeLogic for HttpSourceLogic {
timestamp_sec,
)?;
send_to_children!(segment);
send_to_children(std::any::type_name::<Self>(), &output, segment).await?;
chunk_index += 1;
total_frames += frames_to_emit as u64;
@@ -255,7 +250,7 @@ impl NodeLogic for HttpSourceLogic {
let timestamp_sec = total_frames as f64 / stream_info.sample_rate as f64;
let segment =
bytes_to_segment(&pending, &stream_info, frames, chunk_index, timestamp_sec)?;
send_to_children!(segment);
send_to_children(std::any::type_name::<Self>(), &output, segment).await?;
total_frames += frames as u64;
chunk_index += 1;
}
@@ -264,7 +259,7 @@ impl NodeLogic for HttpSourceLogic {
// Émettre EndOfStream
let final_timestamp = total_frames as f64 / stream_info.sample_rate as f64;
let eos = AudioSegment::new_end_of_stream(chunk_index, final_timestamp);
send_to_children!(eos);
send_to_children(std::any::type_name::<Self>(), &output, eos).await?;
// Attendre la fin du décodage
stream

View File

@@ -31,7 +31,7 @@
use crate::{
dsp::resampling::{build_resampler, resampling, Resampler},
nodes::{AudioError, TypedAudioNode},
pipeline::{AudioPipelineNode, Node, NodeLogic},
pipeline::{send_to_children, AudioPipelineNode, Node, NodeLogic},
type_constraints::TypeRequirement,
AudioChunk, AudioChunkData, AudioSegment, BitDepth, I24,
};
@@ -172,12 +172,7 @@ impl NodeLogic for ResamplingLogic {
segment
};
// Envoyer à tous les enfants
for tx in &output {
tx.send(output_segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
send_to_children(std::any::type_name::<Self>(), &output, output_segment).await?;
}
Ok(())

View File

@@ -52,7 +52,7 @@
use crate::{
nodes::{AudioError, TypedAudioNode, DEFAULT_CHANNEL_SIZE, DEFAULT_CHUNK_DURATION_MS},
pipeline::{AudioPipelineNode, Node, NodeLogic},
pipeline::{send_to_children, AudioPipelineNode, Node, NodeLogic},
type_constraints::TypeRequirement,
AudioSegment, SyncMarker, _AudioSegment,
};
@@ -135,11 +135,7 @@ impl TimerBufferNodeLogic {
self.buffer.len()
);
for tx in output {
tx.send(segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
send_to_children(std::any::type_name::<Self>(), output, segment).await?;
}
Ok(())
}
@@ -228,11 +224,12 @@ impl NodeLogic for TimerBufferNodeLogic {
}
// Propager le marker immédiatement
for tx in &output {
tx.send(segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
}
send_to_children(
std::any::type_name::<Self>(),
&output,
segment.clone(),
)
.await?;
}
_AudioSegment::Chunk(chunk) => {

View File

@@ -53,7 +53,7 @@
use crate::{
nodes::{AudioError, TypedAudioNode, DEFAULT_CHANNEL_SIZE},
pipeline::{AudioPipelineNode, Node, NodeLogic},
pipeline::{send_to_children_with_timing, AudioPipelineNode, Node, NodeLogic},
type_constraints::TypeRequirement,
AudioSegment, SyncMarker, _AudioSegment,
};
@@ -132,27 +132,6 @@ impl NodeLogic for TimerNodeLogic {
output.len()
);
// Macro helper pour envoyer à tous les enfants
macro_rules! send_to_children {
($segment:expr) => {
for (idx, tx) in output.iter().enumerate() {
let send_start = Instant::now();
tx.send($segment.clone())
.await
.map_err(|_| AudioError::ChildDied)?;
let send_duration = send_start.elapsed();
if send_duration.as_millis() >= 50 {
tracing::debug!(
"TimerNode: send to child {} blocked for {:.3}s (segment ts={:.3}s)",
idx,
send_duration.as_secs_f64(),
$segment.timestamp_sec
);
}
}
};
}
loop {
let segment = tokio::select! {
_ = stop_token.cancelled() => {
@@ -184,7 +163,23 @@ impl NodeLogic for TimerNodeLogic {
// Autres markers: passthrough transparent
}
}
send_to_children!(segment);
let segment_ts = segment.timestamp_sec;
send_to_children_with_timing(
std::any::type_name::<Self>(),
&output,
segment.clone(),
|idx, send_duration, _capacity_before| {
if send_duration.as_millis() >= 50 {
tracing::debug!(
"TimerNode: send to child {} blocked for {:.3}s (segment ts={:.3}s)",
idx,
send_duration.as_secs_f64(),
segment_ts
);
}
},
)
.await?;
}
_AudioSegment::Chunk(_) => {
@@ -263,7 +258,23 @@ impl NodeLogic for TimerNodeLogic {
tracing::warn!("TimerNodeLogic: NO TIMER SET - passthrough without pacing! (ts={:.3}s)", segment.timestamp_sec);
}
send_to_children!(segment);
let segment_ts = segment.timestamp_sec;
send_to_children_with_timing(
std::any::type_name::<Self>(),
&output,
segment.clone(),
|idx, send_duration, _capacity_before| {
if send_duration.as_millis() >= 50 {
tracing::debug!(
"TimerNode: send to child {} blocked for {:.3}s (segment ts={:.3}s)",
idx,
send_duration.as_secs_f64(),
segment_ts
);
}
},
)
.await?;
}
}
}