[fix](trx-frontend-http): reconfigure audio stream on rig change
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -2642,6 +2642,40 @@ function clearTxTimeout() {
|
||||
txTimeoutRemaining = 0;
|
||||
}
|
||||
|
||||
function resetRxDecoder() {
|
||||
if (opusDecoder) {
|
||||
try { opusDecoder.close(); } catch (e) {}
|
||||
opusDecoder = null;
|
||||
}
|
||||
nextPlayTime = 0;
|
||||
}
|
||||
|
||||
function configureRxStream(nextInfo) {
|
||||
const nextSampleRate = (nextInfo && nextInfo.sample_rate) || 48000;
|
||||
const sampleRateChanged = !audioCtx || audioCtx.sampleRate !== nextSampleRate;
|
||||
streamInfo = nextInfo;
|
||||
updateWfmControls();
|
||||
resetRxDecoder();
|
||||
if (sampleRateChanged && audioCtx) {
|
||||
audioCtx.close().catch(() => {});
|
||||
audioCtx = null;
|
||||
rxGainNode = null;
|
||||
}
|
||||
if (!audioCtx) {
|
||||
audioCtx = new AudioContext({ sampleRate: nextSampleRate });
|
||||
audioCtx.resume().catch(() => {});
|
||||
}
|
||||
if (!rxGainNode) {
|
||||
rxGainNode = audioCtx.createGain();
|
||||
rxGainNode.connect(audioCtx.destination);
|
||||
}
|
||||
rxGainNode.gain.value = rxVolSlider.value / 100;
|
||||
rxActive = true;
|
||||
rxAudioBtn.style.borderColor = "#00d17f";
|
||||
rxAudioBtn.style.color = "#00d17f";
|
||||
audioStatus.textContent = "RX";
|
||||
}
|
||||
|
||||
function startRxAudio() {
|
||||
if (rxActive) { stopRxAudio(); return; }
|
||||
if (!hasWebCodecs) {
|
||||
@@ -2661,17 +2695,7 @@ function startRxAudio() {
|
||||
if (typeof evt.data === "string") {
|
||||
// Stream info JSON
|
||||
try {
|
||||
streamInfo = JSON.parse(evt.data);
|
||||
updateWfmControls();
|
||||
audioCtx = new AudioContext({ sampleRate: streamInfo.sample_rate || 48000 });
|
||||
audioCtx.resume().catch(() => {});
|
||||
rxGainNode = audioCtx.createGain();
|
||||
rxGainNode.gain.value = rxVolSlider.value / 100;
|
||||
rxGainNode.connect(audioCtx.destination);
|
||||
rxActive = true;
|
||||
rxAudioBtn.style.borderColor = "#00d17f";
|
||||
rxAudioBtn.style.color = "#00d17f";
|
||||
audioStatus.textContent = "RX";
|
||||
configureRxStream(JSON.parse(evt.data));
|
||||
} catch (e) {
|
||||
console.error("Audio stream info parse error", e);
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ pub async fn audio_ws(
|
||||
let (response, mut session, mut msg_stream) = actix_ws::handle(&req, body)?;
|
||||
|
||||
actix_web::rt::spawn(async move {
|
||||
let info = loop {
|
||||
let mut current_info = loop {
|
||||
if let Some(info) = info_rx.borrow().clone() {
|
||||
break info;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ pub async fn audio_ws(
|
||||
}
|
||||
};
|
||||
|
||||
let info_json = match serde_json::to_string(&info) {
|
||||
let info_json = match serde_json::to_string(¤t_info) {
|
||||
Ok(j) => j,
|
||||
Err(_) => {
|
||||
let _ = session.close(None).await;
|
||||
@@ -247,12 +247,35 @@ pub async fn audio_ws(
|
||||
return;
|
||||
}
|
||||
|
||||
let mut rx_session = session.clone();
|
||||
let rx_handle = actix_web::rt::spawn(async move {
|
||||
loop {
|
||||
match rx_sub.recv().await {
|
||||
tokio::select! {
|
||||
changed = info_rx.changed() => {
|
||||
match changed {
|
||||
Ok(()) => {
|
||||
let Some(next_info) = info_rx.borrow().clone() else {
|
||||
continue;
|
||||
};
|
||||
let changed = next_info.sample_rate != current_info.sample_rate
|
||||
|| next_info.channels != current_info.channels
|
||||
|| next_info.frame_duration_ms != current_info.frame_duration_ms;
|
||||
if changed {
|
||||
current_info = next_info;
|
||||
let info_json = match serde_json::to_string(¤t_info) {
|
||||
Ok(j) => j,
|
||||
Err(_) => break,
|
||||
};
|
||||
if session.text(info_json).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
packet = rx_sub.recv() => {
|
||||
match packet {
|
||||
Ok(packet) => {
|
||||
if rx_session.binary(packet).await.is_err() {
|
||||
if session.binary(packet).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -262,19 +285,18 @@ pub async fn audio_ws(
|
||||
Err(broadcast::error::RecvError::Closed) => break,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while let Some(Ok(msg)) = msg_stream.recv().await {
|
||||
msg = msg_stream.recv() => {
|
||||
match msg {
|
||||
Message::Binary(data) => {
|
||||
Some(Ok(Message::Binary(data))) => {
|
||||
let _ = tx_sender.send(Bytes::from(data.to_vec())).await;
|
||||
}
|
||||
Message::Close(_) => break,
|
||||
_ => {}
|
||||
Some(Ok(Message::Close(_))) => break,
|
||||
Some(Ok(_)) => {}
|
||||
Some(Err(_)) | None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rx_handle.abort();
|
||||
let _ = session.close(None).await;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user