From ee7f0360fb406ef75df4487a10295827bfe66dbe Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Sun, 8 Feb 2026 13:07:28 +0100 Subject: [PATCH] [fix](trx-server): pause audio playback stream when idle Start the output stream paused and only play when TX packets arrive. Pause again when the packet queue drains to prevent continuous ALSA buffer underruns (EPIPE errno -32) on Linux. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stanislaw Grams --- src/trx-server/src/audio.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/trx-server/src/audio.rs b/src/trx-server/src/audio.rs index b726b70..530130f 100644 --- a/src/trx-server/src/audio.rs +++ b/src/trx-server/src/audio.rs @@ -224,12 +224,19 @@ fn run_playback( None, )?; - stream.play()?; - info!("Audio playback: started"); + // Start paused — only play when TX packets arrive + info!("Audio playback: ready ({}Hz, {} ch)", sample_rate, channels); let mut pcm_buf = vec![0f32; frame_samples]; + let mut playing = false; while let Some(packet) = rx.blocking_recv() { + if !playing { + stream.play()?; + playing = true; + info!("Audio playback: started"); + } + match decoder.decode_float(&packet, &mut pcm_buf, false) { Ok(decoded) => { let mut ring = ring_writer.lock().unwrap(); @@ -239,6 +246,18 @@ fn run_playback( warn!("Opus decode error: {}", e); } } + + // Pause when no more packets are queued to avoid ALSA underruns + if rx.is_empty() { + // Drain remaining samples before pausing + std::thread::sleep(std::time::Duration::from_millis(frame_duration_ms as u64 * 2)); + if rx.is_empty() { + let _ = stream.pause(); + playing = false; + ring_writer.lock().unwrap().clear(); + info!("Audio playback: paused (idle)"); + } + } } Ok(())