[fix](trx-frontend-http): route vchan commands to correct rig in background decode

BackgroundDecodeManager.send_audio_cmd used the global active_rig_id()
to route virtual channel commands. During a rig switch, Remove commands
for the old rig's channels were sent to the new rig's audio pipeline,
leaving orphaned virtual channels on the previous rig's server.

Replace send_audio_cmd with send_audio_cmd_to_rig that takes an explicit
rig_id, derived from the channel's own rig_id field. Both Remove and
SubscribeBackground commands now reach the correct rig.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-04-03 22:04:11 +02:00
parent 42259d3c0d
commit 919b6c5885
@@ -254,16 +254,14 @@ impl BackgroundDecodeManager {
.and_then(|guard| guard.clone())
}
fn send_audio_cmd(&self, cmd: VChanAudioCmd) {
fn send_audio_cmd_to_rig(&self, rig_id: &str, cmd: VChanAudioCmd) {
// Route through per-rig sender when available.
if let Some(rig_id) = self.active_rig_id() {
if let Ok(map) = self.context.vchan.rig_audio_cmd.read() {
if let Some(tx) = map.get(&rig_id) {
if let Some(tx) = map.get(rig_id) {
let _ = tx.try_send(cmd);
return;
}
}
}
// Fall back to global sender.
if let Ok(guard) = self.context.vchan.audio_cmd.lock() {
if let Some(tx) = guard.as_ref() {
@@ -273,7 +271,7 @@ impl BackgroundDecodeManager {
}
fn remove_channel(&self, channel: &VirtualBackgroundDecodeChannel) {
self.send_audio_cmd(VChanAudioCmd::Remove(channel.uuid));
self.send_audio_cmd_to_rig(&channel.rig_id, VChanAudioCmd::Remove(channel.uuid));
}
fn clear_runtime_channels(&self, runtime: &mut BackgroundRuntimeState) {
@@ -444,13 +442,16 @@ impl BackgroundDecodeManager {
if runtime.active_channels.contains_key(&bookmark_id) {
continue;
}
self.send_audio_cmd(VChanAudioCmd::SubscribeBackground {
self.send_audio_cmd_to_rig(
&desired.rig_id,
VChanAudioCmd::SubscribeBackground {
uuid: desired.uuid,
freq_hz: desired.freq_hz,
mode: desired.mode.clone(),
bandwidth_hz: desired.bandwidth_hz,
decoder_kinds: desired.decoder_kinds.clone(),
});
},
);
runtime.active_channels.insert(bookmark_id, desired);
}