Refactor audio pipeline for multi-client streaming and improved error handling
Refactor the audio pipeline to support multi-client streaming with new OggFlacStreamHandle and StreamingOggFlacSink. - Replace DirectOggFlacSink with StreamingOggFlacSink in pipeline - Update documentation and comments to reflect multi-client support - Add detailed warning logs for buffer underruns and client disconnections - Remove TimerBufferNode from pipeline as it's no longer needed - Update connect() calls to subscribe() for new streaming behavior This change enables multiple clients to subscribe to the same audio stream, with each subscription getting a live feed from the current point in time.
This commit is contained in:
@@ -7,9 +7,12 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use pmoaudio::{AudioSegment, PositionHandle, PositionTrackerNode, ResamplingNode, TimerBufferNode, ToI24Node};
|
||||
use pmoaudio::{AudioSegment, PositionTrackerNode, ResamplingNode, ToI24Node};
|
||||
use pmometadata::{MemoryTrackMetadata, TrackMetadata};
|
||||
use pmoaudio_ext::sinks::{DirectOggFlacHandle, DirectOggFlacSink, DIRECT_OGG_FLAC_SAMPLE_RATE};
|
||||
use pmoaudio_ext::sinks::{
|
||||
OggFlacStreamHandle, StreamingOggFlacSink,
|
||||
DIRECT_OGG_FLAC_BITS_PER_SAMPLE, DIRECT_OGG_FLAC_SAMPLE_RATE,
|
||||
};
|
||||
use pmoaudio_ext::UriSource;
|
||||
use pmoflac::EncoderOptions;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -56,10 +59,10 @@ impl PipelineHandle {
|
||||
/// Pipeline audio complet pour une instance WebRenderer.
|
||||
///
|
||||
/// Créé au `POST /register`. Le flux OGG-FLAC est accessible via `flac_handle`
|
||||
/// (un seul client à la fois, reconnectable à chaque Play).
|
||||
/// (multi-clients, chaque `subscribe()` retourne un nouveau flux depuis le point courant).
|
||||
pub struct InstancePipeline {
|
||||
/// Handle vers le sink OGG-FLAC — clonable, reconnectable à chaque Play.
|
||||
pub flac_handle: DirectOggFlacHandle,
|
||||
/// Handle vers le sink OGG-FLAC — clonable, chaque subscribe() donne un flux live.
|
||||
pub flac_handle: OggFlacStreamHandle,
|
||||
pub pipeline_handle: PipelineHandle,
|
||||
}
|
||||
|
||||
@@ -79,21 +82,18 @@ impl InstancePipeline {
|
||||
// La backpressure remonte naturellement depuis le pipe duplex jusqu'à la source.
|
||||
use pmoaudio::pipeline::AudioPipelineNode;
|
||||
|
||||
let (sink, flac_handle) = DirectOggFlacSink::new(EncoderOptions::default());
|
||||
let (sink, flac_handle) = StreamingOggFlacSink::new(
|
||||
EncoderOptions::default(),
|
||||
DIRECT_OGG_FLAC_BITS_PER_SAMPLE,
|
||||
);
|
||||
|
||||
// Nœud de suivi de position : lit le timestamp des chunks sortant du buffer
|
||||
// Nœud de suivi de position : lit le timestamp des chunks sortant vers le sink
|
||||
let (mut position_tracker, position_handle) = PositionTrackerNode::new();
|
||||
position_tracker.register(sink.boxed());
|
||||
|
||||
// Nœud de pacing : régule le débit pour éviter les rafales et pertes de segments
|
||||
// 2s de buffer absorbe les irrégularités de la source réseau
|
||||
let mut timer_buffer = TimerBufferNode::new(2.0);
|
||||
timer_buffer.register(position_tracker.boxed());
|
||||
|
||||
// Nœud de conversion de profondeur : tout type entier → I24
|
||||
// Placé avant le buffer pour réduire la mémoire utilisée
|
||||
let mut to_i24 = ToI24Node::new();
|
||||
to_i24.register(timer_buffer.boxed());
|
||||
to_i24.register(position_tracker.boxed());
|
||||
|
||||
// Nœud de rééchantillonnage : n'importe quel sample rate → 96 kHz
|
||||
let mut resampler = ResamplingNode::new(DIRECT_OGG_FLAC_SAMPLE_RATE);
|
||||
|
||||
@@ -29,8 +29,8 @@ pub struct WebRendererInstance {
|
||||
pub udn: String,
|
||||
pub device_instance: Arc<DeviceInstance>,
|
||||
pub state: SharedState,
|
||||
/// Handle vers le sink OGG-FLAC — clonable, reconnectable à chaque Play.
|
||||
pub flac_handle: pmoaudio_ext::sinks::DirectOggFlacHandle,
|
||||
/// Handle vers le sink OGG-FLAC — clonable, chaque subscribe() donne un flux live.
|
||||
pub flac_handle: pmoaudio_ext::sinks::OggFlacStreamHandle,
|
||||
pub pipeline: PipelineHandle,
|
||||
pub created_at: SystemTime,
|
||||
}
|
||||
@@ -116,11 +116,11 @@ impl RendererRegistry {
|
||||
Ok((stream_url, udn))
|
||||
}
|
||||
|
||||
/// Retourne le DirectOggFlacHandle pour l'endpoint /stream (clonable).
|
||||
/// Retourne le OggFlacStreamHandle pour l'endpoint /stream (clonable).
|
||||
pub fn get_flac_handle(
|
||||
&self,
|
||||
instance_id: &str,
|
||||
) -> Option<pmoaudio_ext::sinks::DirectOggFlacHandle> {
|
||||
) -> Option<pmoaudio_ext::sinks::OggFlacStreamHandle> {
|
||||
self.instances
|
||||
.read()
|
||||
.get(instance_id)
|
||||
|
||||
@@ -44,7 +44,7 @@ pub async fn stream_handler(
|
||||
}
|
||||
};
|
||||
|
||||
let stream = handle.connect().await;
|
||||
let stream = handle.subscribe();
|
||||
|
||||
info!(instance_id = %instance_id, "FLAC stream started");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user