[fix](trx-frontend-http): scope channel audio by remote

Send the selected remote together with virtual-channel audio requests and use per-rig stream info when /audio is opened with channel_id.

This keeps browser channel audio aligned with the requested remote after the recent multi-rig client changes.

Add coverage for parsing channel_id together with remote.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-24 07:29:57 +01:00
parent db5fa26bd9
commit 80ed1155f5
2 changed files with 24 additions and 2 deletions
@@ -7672,7 +7672,10 @@ function startRxAudio() {
const proto = location.protocol === "https:" ? "wss:" : "ws:"; const proto = location.protocol === "https:" ? "wss:" : "ws:";
let audioPath; let audioPath;
if (_audioChannelOverride) { if (_audioChannelOverride) {
audioPath = `/audio?channel_id=${encodeURIComponent(_audioChannelOverride)}`; const remoteParam = lastActiveRigId
? `&remote=${encodeURIComponent(lastActiveRigId)}`
: "";
audioPath = `/audio?channel_id=${encodeURIComponent(_audioChannelOverride)}${remoteParam}`;
} else if (lastActiveRigId) { } else if (lastActiveRigId) {
audioPath = `/audio?remote=${encodeURIComponent(lastActiveRigId)}`; audioPath = `/audio?remote=${encodeURIComponent(lastActiveRigId)}`;
} else { } else {
@@ -502,7 +502,14 @@ pub async fn audio_ws(
broadcast::Receiver<Bytes>, broadcast::Receiver<Bytes>,
tokio::sync::watch::Receiver<Option<trx_core::audio::AudioStreamInfo>>, tokio::sync::watch::Receiver<Option<trx_core::audio::AudioStreamInfo>>,
) = if let Some(ch_id) = query.channel_id { ) = if let Some(ch_id) = query.channel_id {
let Some(info_rx) = context.audio_info.as_ref().cloned() else { let info_rx = if let Some(ref remote) = query.remote {
context
.rig_audio_info_rx(remote)
.or_else(|| context.audio_info.as_ref().cloned())
} else {
context.audio_info.as_ref().cloned()
};
let Some(info_rx) = info_rx else {
return Ok(HttpResponse::NotFound().body("audio not enabled")); return Ok(HttpResponse::NotFound().body("audio not enabled"));
}; };
let deadline = Instant::now() + Duration::from_secs(2); let deadline = Instant::now() + Duration::from_secs(2);
@@ -636,6 +643,7 @@ pub async fn audio_ws(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::AudioQuery; use super::AudioQuery;
use uuid::Uuid;
#[test] #[test]
fn audio_query_accepts_remote() { fn audio_query_accepts_remote() {
@@ -643,4 +651,15 @@ mod tests {
serde_json::from_str(r#"{"remote":"lidzbark-vhf"}"#).expect("query parse"); serde_json::from_str(r#"{"remote":"lidzbark-vhf"}"#).expect("query parse");
assert_eq!(query.remote.as_deref(), Some("lidzbark-vhf")); assert_eq!(query.remote.as_deref(), Some("lidzbark-vhf"));
} }
#[test]
fn audio_query_accepts_channel_id_with_remote() {
let channel_id = Uuid::new_v4();
let query: AudioQuery = serde_json::from_str(&format!(
r#"{{"channel_id":"{channel_id}","remote":"lidzbark-vhf"}}"#
))
.expect("query parse");
assert_eq!(query.channel_id, Some(channel_id));
assert_eq!(query.remote.as_deref(), Some("lidzbark-vhf"));
}
} }