fix(audio): label streaming decoder logs by source type

Differentiate streaming decoder init/decode messages between queue track streaming and radio so errors are not misattributed to radio playback.
This commit is contained in:
Maxim Isaev
2026-04-17 16:43:43 +03:00
parent c165669db5
commit 1e54946939
+15 -11
View File
@@ -1200,11 +1200,15 @@ impl SizedDecoder {
}) })
} }
/// Build a decoder from any `MediaSource` (e.g. `RadioBuffer`). /// Build a decoder from any `MediaSource` (e.g. track-stream or radio).
/// Uses `enable_gapless: false` — live streams are not seekable; gapless /// Uses `enable_gapless: false` — live streams are not seekable; gapless
/// trimming requires seeking to read the LAME/iTunSMPB end-padding info. /// trimming requires seeking to read the LAME/iTunSMPB end-padding info.
fn new_streaming(media: Box<dyn MediaSource>, format_hint: Option<&str>) -> Result<Self, String> { fn new_streaming(
// Larger read-ahead buffer for the live radio SPSC consumer — reduces media: Box<dyn MediaSource>,
format_hint: Option<&str>,
source_tag: &str,
) -> Result<Self, String> {
// Larger read-ahead buffer for the live streaming SPSC consumer — reduces
// read() call frequency into the ring buffer, easing I/O spikes. // read() call frequency into the ring buffer, easing I/O spikes.
let mss = MediaSourceStream::new(media, MediaSourceStreamOptions { buffer_len: 512 * 1024 }); let mss = MediaSourceStream::new(media, MediaSourceStreamOptions { buffer_len: 512 * 1024 });
let mut hint = Hint::new(); let mut hint = Hint::new();
@@ -1212,16 +1216,16 @@ impl SizedDecoder {
let format_opts = FormatOptions { enable_gapless: false, ..Default::default() }; let format_opts = FormatOptions { enable_gapless: false, ..Default::default() };
let probed = symphonia::default::get_probe() let probed = symphonia::default::get_probe()
.format(&hint, mss, &format_opts, &MetadataOptions::default()) .format(&hint, mss, &format_opts, &MetadataOptions::default())
.map_err(|e| format!("radio: format probe failed: {e}"))?; .map_err(|e| format!("{source_tag}: format probe failed: {e}"))?;
let track = probed.format.tracks().iter() let track = probed.format.tracks().iter()
.find(|t| t.codec_params.codec != CODEC_TYPE_NULL) .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
.ok_or_else(|| "radio: no audio track found".to_string())?; .ok_or_else(|| format!("{source_tag}: no audio track found"))?;
let track_id = track.id; let track_id = track.id;
// Live streams have no known total frame count → total_duration = None. // Live streams have no known total frame count → total_duration = None.
let total_duration = None; let total_duration = None;
let mut decoder = try_make_radio_decoder(&track.codec_params, &DecoderOptions::default()) let mut decoder = try_make_radio_decoder(&track.codec_params, &DecoderOptions::default())
.map_err(|e| format!("radio: codec init failed: {e}"))?; .map_err(|e| format!("{source_tag}: codec init failed: {e}"))?;
let mut format = probed.format; let mut format = probed.format;
let mut errors = 0usize; let mut errors = 0usize;
@@ -1235,12 +1239,12 @@ impl SizedDecoder {
Ok(d) => break d, Ok(d) => break d,
Err(symphonia::core::errors::Error::DecodeError(ref msg)) => { Err(symphonia::core::errors::Error::DecodeError(ref msg)) => {
errors += 1; errors += 1;
eprintln!("[psysonic] radio init: dropped corrupt frame #{errors}: {msg}"); eprintln!("[psysonic] {source_tag} init: dropped corrupt frame #{errors}: {msg}");
if errors >= MAX_CONSECUTIVE_DECODE_ERRORS { if errors >= MAX_CONSECUTIVE_DECODE_ERRORS {
return Err("radio: too many consecutive decode errors".into()); return Err(format!("{source_tag}: too many consecutive decode errors"));
} }
} }
Err(e) => return Err(format!("radio: decode error: {e}")), Err(e) => return Err(format!("{source_tag}: decode error: {e}")),
} }
}; };
let spec = decoded.spec().to_owned(); let spec = decoded.spec().to_owned();
@@ -2349,7 +2353,7 @@ pub async fn audio_play(
), ),
PlayInput::Streaming { reader, format_hint } => { PlayInput::Streaming { reader, format_hint } => {
let decoder = tokio::task::spawn_blocking(move || { let decoder = tokio::task::spawn_blocking(move || {
SizedDecoder::new_streaming(Box::new(reader), format_hint.as_deref()) SizedDecoder::new_streaming(Box::new(reader), format_hint.as_deref(), "track-stream")
}) })
.await .await
.map_err(|e| e.to_string())??; .map_err(|e| e.to_string())??;
@@ -3205,7 +3209,7 @@ pub async fn audio_play_radio(
let hint_clone = fmt_hint.clone(); let hint_clone = fmt_hint.clone();
let decoder = tokio::task::spawn_blocking(move || { let decoder = tokio::task::spawn_blocking(move || {
SizedDecoder::new_streaming(Box::new(reader), hint_clone.as_deref()) SizedDecoder::new_streaming(Box::new(reader), hint_clone.as_deref(), "radio")
}) })
.await .await
.map_err(|e| e.to_string())??; .map_err(|e| e.to_string())??;