From 34d0ec8ca8ec3d3b4502a848d9ea79bcfa0e0225 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Thu, 12 Mar 2026 22:57:18 +0100 Subject: [PATCH] [feat](trx-server): add aprs and ais background decoders Co-authored-by: OpenAI Codex Signed-off-by: Stan Grams --- src/trx-server/src/audio.rs | 84 +++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/trx-server/src/audio.rs b/src/trx-server/src/audio.rs index 6ceaec7..75568c7 100644 --- a/src/trx-server/src/audio.rs +++ b/src/trx-server/src/audio.rs @@ -1817,6 +1817,72 @@ async fn run_background_hf_aprs_decoder( } } +async fn run_background_aprs_decoder( + sample_rate: u32, + channels: u16, + mut pcm_rx: broadcast::Receiver>, + decode_tx: broadcast::Sender, +) { + info!( + "Background APRS decoder started ({}Hz, {} ch)", + sample_rate, channels + ); + let mut decoder = AprsDecoder::new(sample_rate); + + loop { + match pcm_rx.recv().await { + Ok(frame) => { + let mut mono = downmix_if_needed(frame, channels); + apply_decode_audio_gate(&mut mono); + for mut pkt in decoder.process_samples(&mono) { + if !pkt.crc_ok { + continue; + } + if pkt.ts_ms.is_none() { + pkt.ts_ms = Some(current_timestamp_ms()); + } + let _ = decode_tx.send(DecodedMessage::Aprs(pkt)); + } + } + Err(broadcast::error::RecvError::Lagged(n)) => { + warn!("Background APRS decoder: dropped {} PCM frames", n); + } + Err(broadcast::error::RecvError::Closed) => break, + } + } +} + +async fn run_background_ais_decoder( + sample_rate: u32, + channels: u16, + mut pcm_rx: broadcast::Receiver>, + decode_tx: broadcast::Sender, +) { + info!( + "Background AIS decoder started ({}Hz, {} ch)", + sample_rate, channels + ); + let mut decoder = AisDecoder::new(sample_rate); + + loop { + match pcm_rx.recv().await { + Ok(frame) => { + let mono = downmix_if_needed(frame, channels); + for mut msg in decoder.process_samples(&mono, "A") { + if msg.ts_ms.is_none() { + msg.ts_ms = Some(current_timestamp_ms()); + } + let _ = decode_tx.send(DecodedMessage::Ais(msg)); + } + } + Err(broadcast::error::RecvError::Lagged(n)) => { + warn!("Background AIS decoder: dropped {} PCM frames", n); + } + Err(broadcast::error::RecvError::Closed) => break, + } + } +} + async fn run_background_ft8_decoder( sample_rate: u32, channels: u16, @@ -2287,6 +2353,24 @@ async fn handle_audio_client( let ch_count = opus_channels as u16; let kind = kind.to_ascii_lowercase(); let handle = match kind.as_str() { + "aprs" => tokio::spawn(async move { + run_background_aprs_decoder( + sr, + ch_count, + task_rx, + decode_tx, + ) + .await; + }), + "ais" => tokio::spawn(async move { + run_background_ais_decoder( + sr, + ch_count, + task_rx, + decode_tx, + ) + .await; + }), "ft8" => tokio::spawn(async move { run_background_ft8_decoder( sr,