[refactor](trx-client): switch VChanAudioCmd to bounded channels (cap 256)

Replace unbounded_channel with channel(256) for VChanAudioCmd to prevent
unlimited memory accumulation under backpressure. Use try_send in
synchronous contexts.

https://claude.ai/code/session_01XzurkeuUmamBuhQwxVy7T4
Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2026-03-25 22:42:55 +00:00
committed by Stan Grams
parent c3abc5ff5b
commit 635a1214d0
4 changed files with 16 additions and 15 deletions
@@ -254,7 +254,7 @@ impl BackgroundDecodeManager {
if let Some(rig_id) = self.active_rig_id() {
if let Ok(map) = self.context.rig_vchan_audio_cmd.read() {
if let Some(tx) = map.get(&rig_id) {
let _ = tx.send(cmd);
let _ = tx.try_send(cmd);
return;
}
}
@@ -262,7 +262,7 @@ impl BackgroundDecodeManager {
// Fall back to global sender.
if let Ok(guard) = self.context.vchan_audio_cmd.lock() {
if let Some(tx) = guard.as_ref() {
let _ = tx.send(cmd);
let _ = tx.try_send(cmd);
}
}
}
@@ -108,16 +108,16 @@ pub struct ClientChannelManager {
pub change_tx: broadcast::Sender<String>,
pub max_channels: usize,
/// Global fallback sender to the audio-client task for virtual-channel audio commands.
pub audio_cmd: std::sync::Mutex<Option<mpsc::UnboundedSender<VChanAudioCmd>>>,
pub audio_cmd: std::sync::Mutex<Option<mpsc::Sender<VChanAudioCmd>>>,
/// Per-rig vchan command senders. Commands are routed to the per-rig sender
/// when available, falling back to the global `audio_cmd`.
pub rig_vchan_audio_cmd: Arc<RwLock<HashMap<String, mpsc::UnboundedSender<VChanAudioCmd>>>>,
pub rig_vchan_audio_cmd: Arc<RwLock<HashMap<String, mpsc::Sender<VChanAudioCmd>>>>,
}
impl ClientChannelManager {
pub fn new(
max_channels: usize,
rig_vchan_audio_cmd: Arc<RwLock<HashMap<String, mpsc::UnboundedSender<VChanAudioCmd>>>>,
rig_vchan_audio_cmd: Arc<RwLock<HashMap<String, mpsc::Sender<VChanAudioCmd>>>>,
) -> Self {
let (change_tx, _) = broadcast::channel(64);
Self {
@@ -131,7 +131,7 @@ impl ClientChannelManager {
}
/// Wire the global audio-command sender as fallback.
pub fn set_audio_cmd(&self, tx: mpsc::UnboundedSender<VChanAudioCmd>) {
pub fn set_audio_cmd(&self, tx: mpsc::Sender<VChanAudioCmd>) {
*self.audio_cmd.lock().unwrap() = Some(tx);
}
@@ -141,13 +141,13 @@ impl ClientChannelManager {
// Try per-rig sender first.
if let Ok(map) = self.rig_vchan_audio_cmd.read() {
if let Some(tx) = map.get(rig_id) {
let _ = tx.send(cmd);
let _ = tx.try_send(cmd);
return;
}
}
// Fall back to global sender.
if let Some(tx) = self.audio_cmd.lock().unwrap().as_ref() {
let _ = tx.send(cmd);
let _ = tx.try_send(cmd);
}
}