Fabriquans un object Channel dans RadioRaradise
This commit is contained in:
@@ -22,14 +22,14 @@
|
||||
//! Aucune des crates ci-dessus ne dépend de `pmoaudio-ext`, évitant ainsi
|
||||
//! tout cycle de dépendances.
|
||||
|
||||
#[cfg(feature = "cache-sink")]
|
||||
#[cfg(any(feature = "cache-sink", feature = "http-stream"))]
|
||||
pub mod sinks;
|
||||
|
||||
#[cfg(feature = "playlist")]
|
||||
pub mod sources;
|
||||
|
||||
// Re-exports pour faciliter l'utilisation
|
||||
#[cfg(feature = "cache-sink")]
|
||||
#[cfg(any(feature = "cache-sink", feature = "http-stream"))]
|
||||
pub use sinks::*;
|
||||
|
||||
#[cfg(feature = "playlist")]
|
||||
|
||||
@@ -76,10 +76,7 @@ impl BroadcastPacer {
|
||||
if lead_time < 0.0 {
|
||||
warn!(
|
||||
"{}: Dropping late frame: audio_ts={:.3}s, elapsed={:.3}s, lag={:.3}s",
|
||||
self.label,
|
||||
audio_timestamp,
|
||||
elapsed,
|
||||
-lead_time
|
||||
self.label, audio_timestamp, elapsed, -lead_time
|
||||
);
|
||||
return Err(SkipFrame);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
@@ -177,6 +177,8 @@ pub struct StreamHandle {
|
||||
|
||||
/// Cached FLAC header (sent to new subscribers first)
|
||||
flac_header: Arc<RwLock<Option<Bytes>>>,
|
||||
|
||||
auto_stop: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl StreamHandle {
|
||||
@@ -243,6 +245,11 @@ impl StreamHandle {
|
||||
pub fn should_stop(&self) -> bool {
|
||||
self.active_clients.load(Ordering::SeqCst) == 0
|
||||
}
|
||||
|
||||
/// Enable or disable automatic pipeline shutdown when the last client disconnects.
|
||||
pub fn set_auto_stop(&self, enabled: bool) {
|
||||
self.auto_stop.store(enabled, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
/// State for FLAC stream subscription.
|
||||
@@ -348,8 +355,12 @@ impl Drop for FlacClientStream {
|
||||
debug!("FLAC client disconnected (remaining: {})", count - 1);
|
||||
|
||||
if count == 1 {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,8 +567,12 @@ impl Drop for IcyClientStream {
|
||||
debug!("ICY client disconnected (remaining: {})", count - 1);
|
||||
|
||||
if count == 1 {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1068,6 +1083,7 @@ impl StreamingFlacSink {
|
||||
active_clients,
|
||||
stop_token: stop_token.clone(),
|
||||
flac_header: flac_header.clone(),
|
||||
auto_stop: Arc::new(AtomicBool::new(true)),
|
||||
};
|
||||
|
||||
let logic = StreamingFlacSinkLogic {
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
@@ -114,6 +114,8 @@ pub struct OggFlacStreamHandle {
|
||||
|
||||
/// Cached OGG-FLAC header (sent to new subscribers first)
|
||||
ogg_header: Arc<RwLock<Option<Bytes>>>,
|
||||
|
||||
auto_stop: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl OggFlacStreamHandle {
|
||||
@@ -143,6 +145,10 @@ impl OggFlacStreamHandle {
|
||||
pub fn active_client_count(&self) -> usize {
|
||||
self.active_clients.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn set_auto_stop(&self, enabled: bool) {
|
||||
self.auto_stop.store(enabled, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
/// State for OGG-FLAC stream subscription.
|
||||
@@ -248,8 +254,12 @@ impl Drop for OggFlacClientStream {
|
||||
debug!("OGG-FLAC client disconnected (remaining: {})", count - 1);
|
||||
|
||||
if count == 1 {
|
||||
info!("Last OGG-FLAC client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
if self.handle.auto_stop.load(Ordering::SeqCst) {
|
||||
info!("Last OGG-FLAC client disconnected, signaling pipeline stop");
|
||||
self.handle.stop_token.cancel();
|
||||
} else {
|
||||
info!("Last OGG-FLAC client disconnected, keeping pipeline alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -555,6 +565,7 @@ impl StreamingOggFlacSink {
|
||||
active_clients,
|
||||
stop_token: stop_token.clone(),
|
||||
ogg_header: ogg_header.clone(),
|
||||
auto_stop: Arc::new(AtomicBool::new(true)),
|
||||
};
|
||||
|
||||
let logic = StreamingOggFlacSinkLogic {
|
||||
|
||||
@@ -99,7 +99,7 @@ impl<T> State<T> {
|
||||
}
|
||||
}
|
||||
if purged > 0 {
|
||||
warn!(
|
||||
tracing::debug!(
|
||||
"TimedBroadcast: purged {} expired packet(s) (head_seq={})",
|
||||
purged,
|
||||
self.head_seq
|
||||
@@ -167,10 +167,7 @@ impl<T> Inner<T> {
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
if !self
|
||||
.is_closed
|
||||
.swap(true, Ordering::SeqCst)
|
||||
{
|
||||
if !self.is_closed.swap(true, Ordering::SeqCst) {
|
||||
if let Ok(mut state) = self.state.lock() {
|
||||
state.closed = true;
|
||||
}
|
||||
@@ -185,10 +182,7 @@ pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
|
||||
assert!(capacity > 0, "capacity must be > 0");
|
||||
let inner = Arc::new(Inner::new(capacity));
|
||||
let next_seq = {
|
||||
let state = inner
|
||||
.state
|
||||
.lock()
|
||||
.expect("timed broadcast mutex poisoned");
|
||||
let state = inner.state.lock().expect("timed broadcast mutex poisoned");
|
||||
state.next_seq
|
||||
};
|
||||
let sender = Sender {
|
||||
@@ -198,10 +192,7 @@ pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
|
||||
next_seq: AtomicU64::new(next_seq),
|
||||
});
|
||||
{
|
||||
let mut state = inner
|
||||
.state
|
||||
.lock()
|
||||
.expect("timed broadcast mutex poisoned");
|
||||
let mut state = inner.state.lock().expect("timed broadcast mutex poisoned");
|
||||
state.cursors.push(Arc::downgrade(&cursor));
|
||||
}
|
||||
inner.receiver_count.store(1, Ordering::SeqCst);
|
||||
@@ -257,15 +248,12 @@ impl<T> Sender<T> {
|
||||
}
|
||||
|
||||
if state.buffer.len() < self.inner.capacity {
|
||||
let audio_offset =
|
||||
Duration::from_secs_f64(audio_timestamp.max(0.0));
|
||||
let audio_offset = Duration::from_secs_f64(audio_timestamp.max(0.0));
|
||||
let expires_at = state.epoch_start + audio_offset;
|
||||
let entry = Entry {
|
||||
seq: state.next_seq,
|
||||
expires_at,
|
||||
payload: payload
|
||||
.take()
|
||||
.expect("payload already consumed"),
|
||||
payload: payload.take().expect("payload already consumed"),
|
||||
audio_timestamp,
|
||||
epoch: state.epoch,
|
||||
};
|
||||
@@ -390,19 +378,14 @@ where
|
||||
|
||||
let offset = (self.next_seq - state.head_seq) as usize;
|
||||
if offset < state.buffer.len() {
|
||||
let entry = state
|
||||
.buffer
|
||||
.get(offset)
|
||||
.expect("invalid buffer offset");
|
||||
let entry = state.buffer.get(offset).expect("invalid buffer offset");
|
||||
let packet = TimedPacket {
|
||||
payload: entry.payload.clone(),
|
||||
audio_timestamp: entry.audio_timestamp,
|
||||
epoch: entry.epoch,
|
||||
};
|
||||
self.next_seq += 1;
|
||||
self.cursor
|
||||
.next_seq
|
||||
.store(self.next_seq, Ordering::SeqCst);
|
||||
self.cursor.next_seq.store(self.next_seq, Ordering::SeqCst);
|
||||
if state.prune_consumed() {
|
||||
self.inner.space_notify.notify_waiters();
|
||||
}
|
||||
@@ -460,9 +443,7 @@ impl<T> Clone for Receiver<T> {
|
||||
|
||||
impl<T> Drop for Receiver<T> {
|
||||
fn drop(&mut self) {
|
||||
self.cursor
|
||||
.next_seq
|
||||
.store(self.next_seq, Ordering::SeqCst);
|
||||
self.cursor.next_seq.store(self.next_seq, Ordering::SeqCst);
|
||||
if let Ok(mut state) = self.inner.state.lock() {
|
||||
if state.prune_consumed() {
|
||||
self.inner.space_notify.notify_waiters();
|
||||
|
||||
Reference in New Issue
Block a user