diff --git a/changelog.json b/changelog.json index b8b7bed..69a1a79 100644 --- a/changelog.json +++ b/changelog.json @@ -22,7 +22,8 @@ "Icom network: when the rig goes quiet on CI-V while the session stays up (seen on the IC-7760), the CI-V flow is re-opened on the spot — recovery in seconds instead of the 35-second full reconnect.", "Icom network: after a session dies young, the redial waits 20 s so the rig can purge the old session first — stops the reconnect-die-reconnect spiral seen on the IC-7760, where each fresh session answered for a second and was then strangled by the previous one’s cleanup.", "Icom network audio, phase 5: the radio can now TAKE audio — with RX audio enabled, pick “Radio (network audio)” as the To-radio device and the voice keyer plays straight to the rig over the LAN, no cable, no virtual sound card. First tested on the IC-7760.", - "Icom network audio: listening is now a remembered choice — Stop listening keeps the speakers off across reconnects and restarts, while the stream stays open for the QSO recorder and the voice keyer." + "Icom network audio: listening is now a remembered choice — Stop listening keeps the speakers off across reconnects and restarts, while the stream stays open for the QSO recorder and the voice keyer.", + "Icom console: a speaker button beside ON/OFF toggles listening to the network RX audio right from the console — no more trip through Settings → Audio; recordings and the voice keyer keep working either way, and the choice is remembered." ], "fr": [ "Console Elecraft : le S-mètre est calibré sur un vrai K3 — S9 et les +dB correspondent désormais à l’affichage de la radio (il lisait environ deux points S trop bas).", @@ -44,7 +45,8 @@ "Réseau Icom : quand la radio se tait sur le CI-V alors que la session tient (constaté sur l’IC-7760), le flux CI-V est rouvert immédiatement — récupération en quelques secondes au lieu des 35 secondes de reconnexion complète.", "Réseau Icom : après une session morte jeune, la renumérotation attend 20 s pour que la radio purge d’abord l’ancienne session — stoppe la spirale reconnexion-mort-reconnexion vue sur l’IC-7760, où chaque session neuve répondait une seconde avant d’être étranglée par le nettoyage de la précédente.", "Audio réseau Icom, phase 5 : la radio peut maintenant RECEVOIR de l’audio — avec le RX audio activé, choisissez « Radio (network audio) » comme périphérique To Radio et le voice keyer joue directement vers la radio par le LAN, sans câble ni carte son virtuelle. Premier test sur l’IC-7760.", - "Audio réseau Icom : l’écoute est désormais un choix mémorisé — Stop listening garde les enceintes coupées à travers reconnexions et redémarrages, tandis que le flux reste ouvert pour l’enregistreur de QSO et le voice keyer." + "Audio réseau Icom : l’écoute est désormais un choix mémorisé — Stop listening garde les enceintes coupées à travers reconnexions et redémarrages, tandis que le flux reste ouvert pour l’enregistreur de QSO et le voice keyer.", + "Console Icom : un bouton haut-parleur à côté de ON/OFF bascule l’écoute du RX audio réseau depuis la console — fini l’aller-retour dans Réglages → Audio ; enregistrements et voice keyer continuent de fonctionner, et le choix est mémorisé." ] }, { diff --git a/frontend/src/components/IcomPanel.tsx b/frontend/src/components/IcomPanel.tsx index 84506be..459bc84 100644 --- a/frontend/src/components/IcomPanel.tsx +++ b/frontend/src/components/IcomPanel.tsx @@ -1,9 +1,10 @@ import { useEffect, useRef, useState } from 'react'; -import { Radio, AudioLines, Mic, Activity, SlidersHorizontal, Antenna, Filter, Power } from 'lucide-react'; +import { Radio, AudioLines, Mic, Activity, SlidersHorizontal, Antenna, Filter, Power, Volume2, VolumeX } from 'lucide-react'; import { GetIcomState, IcomRefresh, IcomSetAFGain, IcomSetRFGain, IcomSetNB, IcomSetNBLevel, IcomSetNR, IcomSetNRLevel, IcomSetANF, IcomSetAPF, IcomSetAGC, IcomSetPreamp, IcomSetAtt, IcomSetFilter, + AudioMonitorActive, AudioStartMonitor, AudioStopMonitor, IcomSetRFPower, IcomSetMicGain, IcomSetSplit, IcomTune, IcomSetPTT, IcomSetScope, IcomScopeData, IcomSetScopeMode, IcomSetScopeEdges, GetCATState, SetCATFrequency, SetCATMode, IcomSetRIT, IcomSetRITOn, IcomSetXITOn, @@ -596,6 +597,23 @@ function ScopePanadapter() { // read every cache cycle; DSP set-controls are optimistic and reconcile on the // next poll. Front-panel knob changes for DSP show after ↻ Refresh. export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (rst: string) => void; isNetwork?: boolean } = {}) { + // The speaker toggle lives HERE, next to ON/OFF, because that is where the + // operator is looking — burying "stop listening" behind Settings → Audio + // meant a trip through two panels to mute a radio sitting in the same room. + const [listening, setListening] = useState(false); + useEffect(() => { + if (!isNetwork) return; + let alive = true; + const ask = () => AudioMonitorActive().then((v) => { if (alive) setListening(!!v); }).catch(() => {}); + ask(); + const id = window.setInterval(ask, 2000); + return () => { alive = false; window.clearInterval(id); }; + }, [isNetwork]); + const toggleListening = () => { + const next = !listening; + setListening(next); + (next ? AudioStartMonitor() : Promise.resolve(AudioStopMonitor())).catch(() => setListening(!next)); + }; const { t } = useI18n(); const [st, setSt] = useState(ZERO); const [cat, setCat] = useState(null); // RigState (freq/mode/split) for the VFO display @@ -704,6 +722,14 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r rig's LAN server stays alive in standby, so both work. */} {isNetwork && ( <> +