Tentative de gestion d'un historique
This commit is contained in:
@@ -35,6 +35,7 @@ impl TrackBoundaryCoverNode {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl AudioPipelineNode for TrackBoundaryCoverNode {
|
||||
fn get_tx(&self) -> Option<mpsc::Sender<Arc<AudioSegment>>> {
|
||||
self.inner.get_tx()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//! - Paces broadcast to match audio playback rate
|
||||
|
||||
use std::time::Instant;
|
||||
use tracing::{debug, info, warn};
|
||||
use tracing::{trace, warn};
|
||||
|
||||
/// Error returned when a frame should be skipped (too late)
|
||||
#[derive(Debug)]
|
||||
@@ -56,7 +56,7 @@ impl BroadcastPacer {
|
||||
let elapsed_since_start = self.start_time.elapsed().as_secs_f64();
|
||||
if audio_timestamp < 0.1 && elapsed_since_start > 1.0 {
|
||||
self.start_time = Instant::now();
|
||||
info!(
|
||||
trace!(
|
||||
"{} broadcaster: TopZeroSync detected, resetting timer",
|
||||
self.label
|
||||
);
|
||||
@@ -94,7 +94,7 @@ impl BroadcastPacer {
|
||||
|
||||
// Log pour info si on est très en avance, mais on ne dort PAS
|
||||
if self.max_lead_time > 0.0 && lead_time > self.max_lead_time {
|
||||
debug!(
|
||||
trace!(
|
||||
"{} broadcaster: lead_time={:.3}s > max={:.3}s (audio_ts={:.3}s, elapsed={:.3}s) - relying on natural backpressure",
|
||||
self.label, lead_time, self.max_lead_time, audio_timestamp, elapsed
|
||||
);
|
||||
|
||||
@@ -200,6 +200,7 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
|
||||
// Phase 1: Dispatcher jusqu'à ce que le prebuffer soit terminé
|
||||
let mut end_of_stream_received = false;
|
||||
let mut early_track_boundary_received = false;
|
||||
let mut track_tx_opt = Some(track_tx);
|
||||
let pk = loop {
|
||||
tokio::select! {
|
||||
@@ -221,9 +222,9 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
result = rx.recv() => {
|
||||
match result {
|
||||
Some(segment) => {
|
||||
// Si EndOfStream a été reçu, ignorer tous les segments suivants
|
||||
// Si EndOfStream ou TrackBoundary a été reçu, ignorer tous les segments suivants
|
||||
// et continuer à attendre cache_future
|
||||
if end_of_stream_received {
|
||||
if end_of_stream_received || early_track_boundary_received {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -239,10 +240,18 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
}
|
||||
}
|
||||
_AudioSegment::Sync(marker) => match &**marker {
|
||||
SyncMarker::TrackBoundary { .. } => {
|
||||
// TrackBoundary avant fin du prebuffer - track trop courte
|
||||
tracing::error!("FlacCacheSink: TrackBoundary received before prebuffer complete - track too short");
|
||||
return Err(AudioError::ProcessingError("Track too short for prebuffer".to_string()));
|
||||
SyncMarker::TrackBoundary { metadata } => {
|
||||
// TrackBoundary pendant le prebuffer - track courte (< 512KB)
|
||||
tracing::warn!(
|
||||
"FlacCacheSink: TrackBoundary received before prebuffer complete - track shorter than 512KB, closing pump and waiting for ingestion"
|
||||
);
|
||||
// Stocker les métadonnées pour la prochaine track
|
||||
next_track_metadata = Some(metadata.clone());
|
||||
// Fermer le track_tx pour que le pump se termine proprement
|
||||
track_tx_opt = None;
|
||||
// Marquer qu'on a reçu un TrackBoundary précoce
|
||||
early_track_boundary_received = true;
|
||||
// Continuer à attendre cache_future
|
||||
}
|
||||
SyncMarker::EndOfStream => {
|
||||
tracing::debug!("FlacCacheSink: EndOfStream during prebuffer - closing pump and waiting for ingestion to complete");
|
||||
@@ -262,7 +271,7 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
}
|
||||
None => {
|
||||
// EOF sur rx pendant le prebuffer - attendre que cache_future se termine
|
||||
if !end_of_stream_received {
|
||||
if !end_of_stream_received && !early_track_boundary_received {
|
||||
tracing::debug!("FlacCacheSink: EOF on rx during prebuffer, waiting for ingestion to complete");
|
||||
track_tx_opt = None;
|
||||
end_of_stream_received = true;
|
||||
@@ -296,26 +305,62 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
))
|
||||
})?;
|
||||
|
||||
let url = match dest_metadata.read().await.get_cover_url().await {
|
||||
Ok(url) => {
|
||||
tracing::debug!("FlacCacheSink: Got cover URL for pk {}: {:?}", pk, url);
|
||||
url
|
||||
let cover_pk_present = match dest_metadata.read().await.get_cover_pk().await {
|
||||
Ok(Some(existing_pk)) => {
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: cover_pk already set for audio asset {} ({})",
|
||||
pk,
|
||||
existing_pk
|
||||
);
|
||||
true
|
||||
}
|
||||
Ok(None) => false,
|
||||
Err(e) if e.is_transient() => {
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: Transient error getting cover URL for pk {}: {}",
|
||||
"FlacCacheSink: Transient error getting cover_pk for pk {}: {}",
|
||||
pk,
|
||||
e
|
||||
);
|
||||
None
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(
|
||||
"FlacCacheSink: Cannot obtain cover URL for audio asset {}: {}",
|
||||
"FlacCacheSink: Cannot obtain cover_pk for audio asset {}: {}",
|
||||
pk,
|
||||
e
|
||||
);
|
||||
None
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let url = if cover_pk_present {
|
||||
None
|
||||
} else {
|
||||
match dest_metadata.read().await.get_cover_url().await {
|
||||
Ok(url) => {
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: Got cover URL for pk {}: {:?}",
|
||||
pk,
|
||||
url
|
||||
);
|
||||
url
|
||||
}
|
||||
Err(e) if e.is_transient() => {
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: Transient error getting cover URL for pk {}: {}",
|
||||
pk,
|
||||
e
|
||||
);
|
||||
None
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(
|
||||
"FlacCacheSink: Cannot obtain cover URL for audio asset {}: {}",
|
||||
pk,
|
||||
e
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -378,6 +423,16 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
continue; // Passer à la track suivante (qui n'arrivera pas car EndOfStream)
|
||||
}
|
||||
|
||||
// Si TrackBoundary précoce a été reçu pendant le prebuffer, passer à la track suivante
|
||||
if early_track_boundary_received {
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: TrackBoundary was received during prebuffer, track complete, moving to next track"
|
||||
);
|
||||
drop(pump_handle);
|
||||
track_number += 1;
|
||||
continue; // Passer à la track suivante (métadonnées déjà stockées dans next_track_metadata)
|
||||
}
|
||||
|
||||
// Phase 3: Continuer à dispatcher jusqu'au TrackBoundary
|
||||
tracing::debug!(
|
||||
"FlacCacheSink: Continuing dispatch until TrackBoundary (pump runs in background)"
|
||||
|
||||
@@ -79,7 +79,7 @@ use pmometadata::TrackMetadata;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf};
|
||||
use tokio::sync::{mpsc, RwLock};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use tracing::{debug, error, trace, warn};
|
||||
|
||||
/// Default ICY metadata interval (bytes of audio between metadata blocks).
|
||||
/// Standard value used by most streaming servers.
|
||||
@@ -291,7 +291,7 @@ impl AsyncRead for FlacClientStream {
|
||||
|
||||
if let Some(header) = header_opt {
|
||||
self.buffer.extend(header.iter());
|
||||
info!(
|
||||
debug!(
|
||||
"Sending cached FLAC header to new client ({} bytes)",
|
||||
header.len()
|
||||
);
|
||||
@@ -356,10 +356,10 @@ impl Drop for FlacClientStream {
|
||||
|
||||
if count == 1 {
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
debug!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last client disconnected, keeping pipeline alive");
|
||||
debug!("Last client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +465,7 @@ impl AsyncRead for IcyClientStream {
|
||||
|
||||
if let Some(header) = header_opt {
|
||||
self.buffer.extend(header.iter());
|
||||
info!(
|
||||
debug!(
|
||||
"Sending cached FLAC header to new ICY client ({} bytes)",
|
||||
header.len()
|
||||
);
|
||||
@@ -568,10 +568,10 @@ impl Drop for IcyClientStream {
|
||||
|
||||
if count == 1 {
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
debug!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last client disconnected, keeping pipeline alive");
|
||||
debug!("Last client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -603,7 +603,7 @@ impl StreamingFlacSinkLogic {
|
||||
return Ok(()); // Already initialized
|
||||
}
|
||||
|
||||
info!(
|
||||
debug!(
|
||||
"Initializing FLAC encoder with sample rate: {} Hz",
|
||||
sample_rate
|
||||
);
|
||||
@@ -634,7 +634,7 @@ impl StreamingFlacSinkLogic {
|
||||
AudioError::ProcessingError(format!("Failed to start FLAC encoder: {}", e))
|
||||
})?;
|
||||
|
||||
info!("FLAC encoder initialized successfully");
|
||||
debug!("FLAC encoder initialized successfully");
|
||||
|
||||
// Spawn broadcaster task with timestamp for pacing
|
||||
let flac_broadcast = self.flac_broadcast.clone();
|
||||
@@ -656,7 +656,7 @@ impl StreamingFlacSinkLogic {
|
||||
|
||||
self.encoder_state = Some(EncoderState { broadcaster_task });
|
||||
|
||||
info!("Broadcaster task spawned");
|
||||
debug!("Broadcaster task spawned");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -716,7 +716,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
AudioError::ProcessingError("StreamingFlacSink requires an input".into())
|
||||
})?;
|
||||
|
||||
info!("StreamingFlacSink started");
|
||||
debug!("StreamingFlacSink started");
|
||||
|
||||
// We'll initialize the encoder lazily when we get the first chunk
|
||||
// For now, just process segments
|
||||
@@ -724,7 +724,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = stop_token.cancelled() => {
|
||||
info!("StreamingFlacSink stopped by cancellation");
|
||||
debug!("StreamingFlacSink stopped by cancellation");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -737,7 +737,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
if self.sample_rate.is_none() {
|
||||
let sample_rate = chunk.sample_rate();
|
||||
self.sample_rate = Some(sample_rate);
|
||||
info!("Detected sample rate: {} Hz", sample_rate);
|
||||
debug!("Detected sample rate: {} Hz", sample_rate);
|
||||
|
||||
// Initialize the FLAC encoder now
|
||||
self.initialize_encoder(sample_rate).await?;
|
||||
@@ -765,11 +765,11 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
}
|
||||
let send_duration = send_start.elapsed();
|
||||
if send_duration.as_millis() >= 50 {
|
||||
debug!(
|
||||
"StreamingFlacSink: pcm_tx send blocked for {:.3}s (ts={:.3}s)",
|
||||
send_duration.as_secs_f64(),
|
||||
seg.timestamp_sec
|
||||
);
|
||||
trace!(
|
||||
"StreamingFlacSink: pcm_tx send blocked for {:.3}s (ts={:.3}s)",
|
||||
send_duration.as_secs_f64(),
|
||||
seg.timestamp_sec
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +782,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
}
|
||||
|
||||
SyncMarker::EndOfStream => {
|
||||
info!("End of stream marker received");
|
||||
debug!("End of stream marker received");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -800,7 +800,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
}
|
||||
|
||||
None => {
|
||||
info!("Input channel closed");
|
||||
debug!("Input channel closed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -808,12 +808,12 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
}
|
||||
}
|
||||
|
||||
info!("StreamingFlacSink processing complete");
|
||||
debug!("StreamingFlacSink processing complete");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cleanup(&mut self, reason: StopReason) -> Result<(), AudioError> {
|
||||
info!("StreamingFlacSink cleanup: {:?}", reason);
|
||||
debug!("StreamingFlacSink cleanup: {:?}", reason);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -828,7 +828,7 @@ async fn broadcast_flac_stream(
|
||||
current_timestamp: Arc<RwLock<f64>>,
|
||||
broadcast_max_lead_time: f64,
|
||||
) -> Result<(), AudioError> {
|
||||
info!(
|
||||
trace!(
|
||||
"Broadcaster task started with FLAC frame boundary detection (max_lead={:.3}s)",
|
||||
broadcast_max_lead_time
|
||||
);
|
||||
@@ -861,7 +861,7 @@ async fn broadcast_flac_stream(
|
||||
break;
|
||||
}
|
||||
}
|
||||
info!("FLAC encoder stream ended, total bytes: {}", total_bytes);
|
||||
trace!("FLAC encoder stream ended, total bytes: {}", total_bytes);
|
||||
break;
|
||||
}
|
||||
Ok(n) => {
|
||||
@@ -870,7 +870,7 @@ async fn broadcast_flac_stream(
|
||||
total_read_time += read_duration;
|
||||
|
||||
if read_duration > 0.01 {
|
||||
debug!(
|
||||
trace!(
|
||||
"FLAC: flac_stream.read() took {:.3}s for {} bytes (avg: {:.3}s over {} reads)",
|
||||
read_duration,
|
||||
n,
|
||||
@@ -924,7 +924,7 @@ async fn broadcast_flac_stream(
|
||||
let audio_timestamp = *current_timestamp.read().await;
|
||||
|
||||
if stats_last_log.elapsed() >= Duration::from_secs(1) {
|
||||
debug!(
|
||||
trace!(
|
||||
"Broadcaster pacing snapshot: audio_ts={:.3}s buffer_bytes={}",
|
||||
audio_timestamp,
|
||||
accumulator.len()
|
||||
@@ -951,7 +951,7 @@ async fn broadcast_flac_stream(
|
||||
|
||||
// Log if interval is unusual (too short = burst, too long = stall)
|
||||
if broadcast_interval < 0.01 || broadcast_interval > 0.1 {
|
||||
debug!(
|
||||
trace!(
|
||||
"FLAC: broadcast interval {:.3}s ({}ms) - size={} bytes (count={})",
|
||||
broadcast_interval,
|
||||
(broadcast_interval * 1000.0) as u32,
|
||||
@@ -962,7 +962,7 @@ async fn broadcast_flac_stream(
|
||||
|
||||
// Periodic stats
|
||||
if broadcast_count % 100 == 0 {
|
||||
debug!(
|
||||
trace!(
|
||||
"FLAC: {} broadcasts sent, accumulator={} bytes remaining",
|
||||
broadcast_count,
|
||||
accumulator.len()
|
||||
@@ -973,7 +973,7 @@ async fn broadcast_flac_stream(
|
||||
if !header_captured && bytes.len() >= 4 && &bytes[0..4] == b"fLaC" {
|
||||
*header_cache.write().await = Some(bytes.clone());
|
||||
header_captured = true;
|
||||
info!("FLAC header captured ({} bytes)", bytes.len());
|
||||
trace!("FLAC header captured ({} bytes)", bytes.len());
|
||||
}
|
||||
|
||||
let num_receivers = broadcast_tx.receiver_count();
|
||||
@@ -1013,7 +1013,7 @@ async fn broadcast_flac_stream(
|
||||
)));
|
||||
}
|
||||
|
||||
info!("Broadcaster task completed successfully");
|
||||
trace!("Broadcaster task completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1062,7 +1062,7 @@ impl StreamingFlacSink {
|
||||
|
||||
// Calculate broadcast capacity based on max_lead_time
|
||||
let broadcast_capacity = calculate_broadcast_capacity(broadcast_max_lead_time);
|
||||
info!(
|
||||
debug!(
|
||||
"StreamingFlacSink: using broadcast capacity of {} items (max_lead_time={:.1}s)",
|
||||
broadcast_capacity, broadcast_max_lead_time
|
||||
);
|
||||
|
||||
@@ -191,7 +191,7 @@ impl AsyncRead for OggFlacClientStream {
|
||||
|
||||
if let Some(header) = header_opt {
|
||||
self.buffer.extend(header.iter());
|
||||
info!(
|
||||
debug!(
|
||||
"Sending cached OGG-FLAC header to new client ({} bytes)",
|
||||
header.len()
|
||||
);
|
||||
@@ -255,10 +255,10 @@ impl Drop for OggFlacClientStream {
|
||||
|
||||
if count == 1 {
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last OGG-FLAC client disconnected, signaling pipeline stop");
|
||||
debug!("Last OGG-FLAC client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last OGG-FLAC client disconnected, keeping pipeline alive");
|
||||
debug!("Last OGG-FLAC client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ impl StreamingOggFlacSinkLogic {
|
||||
return Ok(()); // Already initialized
|
||||
}
|
||||
|
||||
info!(
|
||||
debug!(
|
||||
"Initializing OGG-FLAC encoder with sample rate: {} Hz",
|
||||
sample_rate
|
||||
);
|
||||
@@ -321,7 +321,7 @@ impl StreamingOggFlacSinkLogic {
|
||||
AudioError::ProcessingError(format!("Failed to start FLAC encoder: {}", e))
|
||||
})?;
|
||||
|
||||
info!("OGG-FLAC encoder initialized successfully");
|
||||
debug!("OGG-FLAC encoder initialized successfully");
|
||||
|
||||
// Spawn OGG wrapper + broadcaster task with timestamp for pacing
|
||||
let ogg_broadcast = self.ogg_broadcast.clone();
|
||||
@@ -343,7 +343,7 @@ impl StreamingOggFlacSinkLogic {
|
||||
|
||||
self.encoder_state = Some(EncoderState { broadcaster_task });
|
||||
|
||||
info!("OGG broadcaster task spawned");
|
||||
debug!("OGG broadcaster task spawned");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -402,7 +402,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
AudioError::ProcessingError("StreamingOggFlacSink requires an input".into())
|
||||
})?;
|
||||
|
||||
info!("StreamingOggFlacSink started");
|
||||
debug!("StreamingOggFlacSink started");
|
||||
|
||||
// TODO: Implement OGG-FLAC encoding logic
|
||||
// For now, just process segments without encoding
|
||||
@@ -410,7 +410,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = stop_token.cancelled() => {
|
||||
info!("StreamingOggFlacSink stopped by cancellation");
|
||||
debug!("StreamingOggFlacSink stopped by cancellation");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
if self.sample_rate.is_none() {
|
||||
let sample_rate = chunk.sample_rate();
|
||||
self.sample_rate = Some(sample_rate);
|
||||
info!("Detected sample rate: {} Hz", sample_rate);
|
||||
debug!("Detected sample rate: {} Hz", sample_rate);
|
||||
|
||||
// Initialize the FLAC encoder now
|
||||
self.initialize_encoder(sample_rate).await?;
|
||||
@@ -460,7 +460,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
}
|
||||
|
||||
SyncMarker::EndOfStream => {
|
||||
info!("End of stream marker received");
|
||||
debug!("End of stream marker received");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
}
|
||||
|
||||
None => {
|
||||
info!("Input channel closed");
|
||||
debug!("Input channel closed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -486,12 +486,12 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
}
|
||||
}
|
||||
|
||||
info!("StreamingOggFlacSink processing complete");
|
||||
debug!("StreamingOggFlacSink processing complete");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cleanup(&mut self, reason: StopReason) -> Result<(), AudioError> {
|
||||
info!("StreamingOggFlacSink cleanup: {:?}", reason);
|
||||
debug!("StreamingOggFlacSink cleanup: {:?}", reason);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -545,7 +545,7 @@ impl StreamingOggFlacSink {
|
||||
// Broadcast channel for OGG-FLAC bytes
|
||||
// Capacity calculated from max_lead_time to ensure enough buffering
|
||||
let broadcast_capacity = calculate_broadcast_capacity(broadcast_max_lead_time);
|
||||
tracing::debug!(
|
||||
tracing::trace!(
|
||||
"OGG-FLAC broadcast capacity: {} items (for {:.1}s max lead time)",
|
||||
broadcast_capacity,
|
||||
broadcast_max_lead_time
|
||||
@@ -786,7 +786,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
current_timestamp: Arc<RwLock<f64>>,
|
||||
broadcast_max_lead_time: f64,
|
||||
) -> Result<(), AudioError> {
|
||||
info!(
|
||||
trace!(
|
||||
"OGG-FLAC broadcaster task started with FLAC frame boundary detection (max_lead={:.3}s)",
|
||||
broadcast_max_lead_time
|
||||
);
|
||||
@@ -807,16 +807,16 @@ async fn broadcast_ogg_flac_stream(
|
||||
|
||||
// Step 1: Read FLAC header (fLaC + metadata blocks)
|
||||
let flac_header = read_flac_header(&mut flac_stream).await?;
|
||||
info!("Read FLAC header: {} bytes", flac_header.len());
|
||||
trace!("Read FLAC header: {} bytes", flac_header.len());
|
||||
|
||||
// Extract sample rate from STREAMINFO for granule position calculation
|
||||
let sample_rate = extract_sample_rate_from_streaminfo(&flac_header)?;
|
||||
info!("Extracted sample rate from STREAMINFO: {} Hz", sample_rate);
|
||||
trace!("Extracted sample rate from STREAMINFO: {} Hz", sample_rate);
|
||||
|
||||
// Step 2: Create OGG-FLAC identification packet (BOS)
|
||||
// Format according to https://xiph.org/flac/ogg_mapping.html
|
||||
let ogg_flac_id = create_ogg_flac_identification(&flac_header)?;
|
||||
info!(
|
||||
trace!(
|
||||
"Created OGG-FLAC identification packet: {} bytes",
|
||||
ogg_flac_id.len()
|
||||
);
|
||||
@@ -835,7 +835,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
cached_header.extend_from_slice(&comment_bytes);
|
||||
*header_cache.write().await = Some(Bytes::from(cached_header));
|
||||
header_captured = true;
|
||||
info!(
|
||||
trace!(
|
||||
"OGG-FLAC header cached ({} bytes: BOS + Vorbis Comment)",
|
||||
bos_bytes.len() + comment_bytes.len()
|
||||
);
|
||||
@@ -871,7 +871,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
trace!("Broadcast closed before sending final EOS page");
|
||||
break;
|
||||
}
|
||||
info!(
|
||||
trace!(
|
||||
"Sent final EOS page with {} bytes of data",
|
||||
flac_accumulator.len()
|
||||
);
|
||||
@@ -885,10 +885,10 @@ async fn broadcast_ogg_flac_stream(
|
||||
trace!("Broadcast closed before sending empty EOS page");
|
||||
break;
|
||||
}
|
||||
info!("Sent empty EOS page");
|
||||
trace!("Sent empty EOS page");
|
||||
}
|
||||
|
||||
info!(
|
||||
trace!(
|
||||
"OGG-FLAC stream ended, total OGG bytes: {}",
|
||||
total_ogg_bytes
|
||||
);
|
||||
@@ -900,7 +900,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
total_read_time += read_duration;
|
||||
|
||||
if read_duration > 0.01 {
|
||||
debug!(
|
||||
trace!(
|
||||
"OGG: flac_stream.read() took {:.3}s for {} bytes (avg: {:.3}s over {} reads)",
|
||||
read_duration,
|
||||
n,
|
||||
@@ -1002,7 +1002,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
|
||||
// Log if interval is unusual (too short = burst, too long = stall)
|
||||
if broadcast_interval < 0.01 || broadcast_interval > 0.1 {
|
||||
debug!(
|
||||
trace!(
|
||||
"OGG: broadcast interval {:.3}s ({}ms) - frame_size={} bytes, samples={} (count={})",
|
||||
broadcast_interval,
|
||||
(broadcast_interval * 1000.0) as u32,
|
||||
@@ -1014,7 +1014,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
|
||||
// Periodic stats
|
||||
if broadcast_count % 100 == 0 {
|
||||
debug!(
|
||||
trace!(
|
||||
"OGG: {} broadcasts sent, avg_interval={:.3}s, accumulator={} bytes",
|
||||
broadcast_count,
|
||||
last_broadcast_time.elapsed().as_secs_f64() / broadcast_count as f64,
|
||||
@@ -1053,7 +1053,7 @@ async fn broadcast_ogg_flac_stream(
|
||||
)));
|
||||
}
|
||||
|
||||
info!("OGG-FLAC broadcaster task completed successfully");
|
||||
trace!("OGG-FLAC broadcaster task completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1177,7 +1177,7 @@ fn create_ogg_flac_identification(flac_header: &[u8]) -> Result<Vec<u8>, AudioEr
|
||||
let block_length =
|
||||
u32::from_be_bytes([0, flac_header[5], flac_header[6], flac_header[7]]) as usize;
|
||||
|
||||
info!("STREAMINFO block_length = {} bytes", block_length);
|
||||
trace!("STREAMINFO block_length = {} bytes", block_length);
|
||||
|
||||
// STREAMINFO should be exactly 34 bytes of data
|
||||
if block_length != 34 {
|
||||
@@ -1194,7 +1194,7 @@ fn create_ogg_flac_identification(flac_header: &[u8]) -> Result<Vec<u8>, AudioEr
|
||||
// Extract just the STREAMINFO block (type + length + data)
|
||||
let streaminfo = &flac_header[4..4 + streaminfo_size];
|
||||
|
||||
info!(
|
||||
trace!(
|
||||
"Extracted STREAMINFO: {} bytes (type+length+data)",
|
||||
streaminfo.len()
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::{
|
||||
};
|
||||
|
||||
use tokio::sync::Notify;
|
||||
use tracing::warn;
|
||||
use tracing::{trace, warn};
|
||||
|
||||
/// Paquet diffusé contenant la charge utile + méta timing.
|
||||
#[derive(Clone)]
|
||||
@@ -99,7 +99,7 @@ impl<T> State<T> {
|
||||
}
|
||||
}
|
||||
if purged > 0 {
|
||||
tracing::debug!(
|
||||
trace!(
|
||||
"TimedBroadcast: purged {} expired packet(s) (head_seq={})",
|
||||
purged,
|
||||
self.head_seq
|
||||
|
||||
Reference in New Issue
Block a user