Ou encore un peu de factorisation dans les nœuds.
This commit is contained in:
@@ -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(())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user