From 53199642ea7cc660425e896d4bfafc2a1dce2af9 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sat, 7 Mar 2026 10:14:09 +0100 Subject: [PATCH] [fix](trx-server): fix VDES channel routing and IQ sample rate Subscribe to the first sdr.channels[] entry configured as VDES or MARINE instead of always using channel 0. The ChannelDsp IQ tap only emits samples when its own mode is VDES/MARINE, so the two must agree. Fix vdes_sr to mirror channel.rs pipeline_rates(): use audio_sample_rate.max(96_000) as the target rather than the hardcoded 96_000. The two diverge when audio_sample_rate > 96_000, causing the VdesDecoder to use the wrong symbol-to-sample ratio. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Stan Grams --- src/trx-server/src/audio.rs | 2 +- src/trx-server/src/main.rs | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/trx-server/src/audio.rs b/src/trx-server/src/audio.rs index eb3b300..e375c5b 100644 --- a/src/trx-server/src/audio.rs +++ b/src/trx-server/src/audio.rs @@ -1041,7 +1041,7 @@ pub async fn run_ais_decoder( } } -/// Run the VDES decoder task. Only processes PCM when rig mode is VDES or MARINE. +/// Run the VDES decoder task. Only processes IQ when rig mode is VDES or MARINE. pub async fn run_vdes_decoder( sample_rate: u32, mut iq_rx: broadcast::Receiver>>, diff --git a/src/trx-server/src/main.rs b/src/trx-server/src/main.rs index c3ebbc6..1daf5e0 100644 --- a/src/trx-server/src/main.rs +++ b/src/trx-server/src/main.rs @@ -355,7 +355,14 @@ fn build_sdr_rig_from_instance(rig_cfg: &RigInstanceConfig) -> SdrRigBuildResult sdr_rig.subscribe_pcm_channel(ais_channel_base_idx), sdr_rig.subscribe_pcm_channel(ais_channel_base_idx + 1), ); - let vdes_iq = sdr_rig.subscribe_iq_channel(0); + // Subscribe to the first channel configured as VDES or MARINE so that the + // IQ tap in ChannelDsp actually fires. Fall back to channel 0 when no + // explicit VDES channel has been configured. + let vdes_channel_idx = channels + .iter() + .position(|(_, mode, _, _)| matches!(mode, trx_core::rig::state::RigMode::VDES | trx_core::rig::state::RigMode::MARINE)) + .unwrap_or(0); + let vdes_iq = sdr_rig.subscribe_iq_channel(vdes_channel_idx); Ok(( Box::new(sdr_rig) as Box, pcm_rx, @@ -643,8 +650,14 @@ fn spawn_rig_audio_stack( let vdes_decode_tx = decode_tx.clone(); let vdes_shutdown_rx = shutdown_rx.clone(); let vdes_histories = histories.clone(); - let vdes_sr = - (rig_cfg.sdr.sample_rate / (rig_cfg.sdr.sample_rate / 96_000).max(1)).max(1); + // Mirror channel.rs pipeline_rates: target = audio_sr.max(96_000), + // decim = sdr_sr / target, actual IQ rate = sdr_sr / decim. + let vdes_sr = { + let sdr_sr = rig_cfg.sdr.sample_rate; + let target = rig_cfg.audio.sample_rate.max(96_000); + let decim = (sdr_sr / target.max(1)).max(1); + (sdr_sr / decim).max(1) + }; handles.push(tokio::spawn(async move { tokio::select! { _ = audio::run_vdes_decoder(vdes_sr, vdes_iq_rx, vdes_state_rx, vdes_decode_tx, vdes_histories) => {}