✨ Add StreamType for multi-client support and improved UPnP control
- Introduce `Streamtype` enum (Continuous vs Finite) to distinguish radio streams from finite tracks - Enrich `TrackBoundary` sync marker with stream type for proper pause behavior per mode (silence vs backpressure) - Update all sources and sinks to pass `StreamType` when creating track boundaries - Radio Paradise, HTTP source → Continuous (infinite) - Improve UPnP control architecture: pause sends silence for radio, blocks pipeline via backpressure for tracks - Prepare groundwork for multi-client DSP architecture with shared source and per-DSP pipelines
This commit is contained in:
@@ -233,7 +233,7 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
}
|
||||
}
|
||||
_AudioSegment::Sync(marker) => match &**marker {
|
||||
SyncMarker::TrackBoundary { metadata } => {
|
||||
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"
|
||||
@@ -589,7 +589,7 @@ impl NodeLogic for FlacCacheSinkLogic {
|
||||
// Si pump_closed, ignorer silencieusement le chunk
|
||||
}
|
||||
_AudioSegment::Sync(marker) => match &**marker {
|
||||
SyncMarker::TrackBoundary { metadata } => {
|
||||
SyncMarker::TrackBoundary { metadata, .. } => {
|
||||
// Nouveau morceau - fermer le pump si pas déjà fermé
|
||||
tracing::debug!("FlacCacheSink: TrackBoundary received, closing pump and storing metadata for next track");
|
||||
// Stocker les métadonnées pour la prochaine track
|
||||
|
||||
@@ -307,7 +307,7 @@ impl NodeLogic for StreamingFlacSinkLogic {
|
||||
|
||||
_AudioSegment::Sync(marker) => {
|
||||
match marker.as_ref() {
|
||||
SyncMarker::TrackBoundary { metadata } => {
|
||||
SyncMarker::TrackBoundary { metadata, .. } => {
|
||||
// Prepare encoder options (metadata + duration) for the upcoming track.
|
||||
if let Err(e) =
|
||||
self.ctx.prepare_encoder_options_for_track(metadata).await
|
||||
|
||||
@@ -88,8 +88,17 @@ impl IcyClientStream {
|
||||
|
||||
// Add cover URL if we have a cover_pk
|
||||
if let Some(pk) = &meta.cover_pk {
|
||||
#[cfg(feature = "playlist")]
|
||||
let cover_url = pmocache::covers_absolute_url_for_upnp(pk, None);
|
||||
metadata_str.push_str(&format!("StreamUrl='{}';", cover_url));
|
||||
#[cfg(feature = "playlist")]
|
||||
{
|
||||
metadata_str.push_str(&format!("StreamUrl='{}';", cover_url));
|
||||
}
|
||||
#[cfg(not(feature = "playlist"))]
|
||||
{
|
||||
// When playlist feature is not enabled, use relative URL
|
||||
metadata_str.push_str(&format!("StreamUrl='/covers/image/{}/256';", pk));
|
||||
}
|
||||
} else if let Some(url) = &meta.cover_url {
|
||||
// Fallback to external cover URL if no local pk
|
||||
metadata_str.push_str(&format!("StreamUrl='{}';", url));
|
||||
|
||||
@@ -265,7 +265,7 @@ impl NodeLogic for StreamingOggFlacSinkLogic {
|
||||
|
||||
_AudioSegment::Sync(marker) => {
|
||||
match marker.as_ref() {
|
||||
SyncMarker::TrackBoundary { metadata } => {
|
||||
SyncMarker::TrackBoundary { metadata, .. } => {
|
||||
// Inject per-track metadata and duration into the next FLAC header.
|
||||
if let Err(e) =
|
||||
self.ctx.prepare_encoder_options_for_track(metadata).await
|
||||
|
||||
@@ -35,6 +35,7 @@ use pmoaudio::{
|
||||
AudioSegment,
|
||||
nodes::AudioError,
|
||||
pipeline::{AudioPipelineNode, Node, NodeLogic, send_to_children},
|
||||
StreamType,
|
||||
};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
@@ -505,7 +506,7 @@ async fn send_track_boundary(
|
||||
let _ = meta.set_title(Some(u.to_string())).await;
|
||||
}
|
||||
let meta_arc = Arc::new(tokio::sync::RwLock::new(meta));
|
||||
let boundary = AudioSegment::new_track_boundary(0, timestamp_sec, meta_arc);
|
||||
let boundary = AudioSegment::new_track_boundary(0, timestamp_sec, meta_arc, StreamType::Finite);
|
||||
|
||||
send_to_children("PlayerSource", output, boundary).await
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ use pmoaudio::{
|
||||
nodes::{AudioError, TypedAudioNode, DEFAULT_CHUNK_DURATION_MS},
|
||||
pipeline::{send_to_children, AudioPipelineNode, Node, NodeLogic},
|
||||
type_constraints::TypeRequirement,
|
||||
AudioSegment,
|
||||
AudioSegment, StreamType,
|
||||
};
|
||||
use pmoaudiocache::Cache as AudioCache;
|
||||
use pmoflac::decode_audio_stream;
|
||||
@@ -279,7 +279,7 @@ impl NodeLogic for PlaylistSourceLogic {
|
||||
let track_start = std::time::Instant::now();
|
||||
tracing::debug!("PlaylistSourceLogic: emitting TrackBoundary");
|
||||
let metadata_for_boundary = metadata.clone();
|
||||
let boundary = AudioSegment::new_track_boundary(0, 0.0, metadata_for_boundary);
|
||||
let boundary = AudioSegment::new_track_boundary(0, 0.0, metadata_for_boundary, StreamType::Finite);
|
||||
send_to_children(node_name, &output, boundary).await?;
|
||||
|
||||
// Obtenir le chemin du fichier
|
||||
|
||||
Reference in New Issue
Block a user