fix(icom): the audio stream no longer depends on the speakers

The sink — decode + recorder feed — was built only on the success path of
starting the monitor, so speakers-off (the remembered preference) or an
output device that failed to open silently disabled the WHOLE stream: the
session connected audio=false, and a ticked RX-audio checkbox did nothing.
The sink now exists whenever the stream is on; only the monitor obeys the
speaker choice.
This commit is contained in:
2026-08-30 01:53:06 +02:00
parent 58e36667a7
commit ec967e29cf
2 changed files with 24 additions and 31 deletions
+15 -24
View File
@@ -15637,36 +15637,17 @@ func (a *App) reloadCAT() {
// verification (see icomaudio.go) — hence experimental + opt-in. // verification (see icomaudio.go) — hence experimental + opt-in.
acfg, _ := a.GetAudioSettings() acfg, _ := a.GetAudioSettings()
a.audioMgr.StopMonitor() // clear any prior monitor/sink so a re-save restarts cleanly a.audioMgr.StopMonitor() // clear any prior monitor/sink so a re-save restarts cleanly
// Listening is a CHOICE, remembered: an operator sitting next to the // The SINK — decode + recorder feed — exists whenever the stream is
// radio hears it in the room and wants the stream only for the // on. It used to be built only when the speakers were also wanted,
// recorder and the voice keyer. Stop listening turns this off, the // so "speakers off" (or a sink that failed to open) silently turned
// Listen button turns it back on, and reconnects respect it instead // the whole stream off: audio=false on the wire, no recordings, no
// of switching the speakers back on every time. // voice keyer, and a ticked RX-audio checkbox that did nothing.
if a.settingOr(keyAudioMonitorOn, "1") != "1" {
applog.Printf("icom-net audio: stream on, speakers off (Listening was stopped by the operator)")
} else if err := a.audioMgr.StartMonitorSink(acfg.ListeningDevice); err != nil {
applog.Printf("icom-net audio: cannot start output sink: %v", err)
} else {
codec := audio.NewPCM16Codec() codec := audio.NewPCM16Codec()
audioSink = func(payload []byte) { audioSink = func(payload []byte) {
pcm, err := codec.Decode(payload) pcm, err := codec.Decode(payload)
if err != nil { if err != nil {
return return
} }
// The IC-7760 streams TWO-channel LPCM whatever the conninfo
// asks for (rxcodec 0x02 was requested, 1280-byte payloads
// kept arriving — 320 stereo frames per 20 ms tick, right
// channel all zeros). Played as mono that is half-speed
// metallic garble. A stereo-sized packet is folded to its
// left channel; a 640-byte mono packet (a rig that honours
// the request) passes through untouched.
if len(pcm) == 1280 {
mono := make([]byte, len(pcm)/2)
for i := 0; i+3 < len(pcm); i += 4 {
mono[i/2], mono[i/2+1] = pcm[i], pcm[i+1]
}
pcm = mono
}
a.audioMgr.PushMonitorAudio(pcm) a.audioMgr.PushMonitorAudio(pcm)
// And to the QSO recorder, which has no device to capture from // And to the QSO recorder, which has no device to capture from
// on this backend. It drops the samples unless a recording is // on this backend. It drops the samples unless a recording is
@@ -15675,6 +15656,16 @@ func (a *App) reloadCAT() {
a.qsoRec.PushRX(pcm) a.qsoRec.PushRX(pcm)
} }
} }
// Listening is a CHOICE, remembered: an operator sitting next to the
// radio hears it in the room and wants the stream only for the
// recorder and the voice keyer. Stop listening turns this off, the
// Listen button turns it back on, and reconnects respect it instead
// of switching the speakers back on every time.
if a.settingOr(keyAudioMonitorOn, "1") != "1" {
applog.Printf("icom-net audio: stream on, speakers off (Listening was stopped by the operator)")
} else if err := a.audioMgr.StartMonitorSink(acfg.ListeningDevice); err != nil {
applog.Printf("icom-net audio: stream on, but the output sink failed: %v", err)
} else {
applog.Printf("icom-net audio: RX audio streaming ENABLED (experimental) → %q", acfg.ListeningDevice) applog.Printf("icom-net audio: RX audio streaming ENABLED (experimental) → %q", acfg.ListeningDevice)
} }
} }
+4 -2
View File
@@ -26,7 +26,8 @@
"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.", "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.",
"CAT settings: a “Play it through the speakers” checkbox sits under the Icom RX-audio option — the same remembered switch as the consoles speaker button, applied immediately.", "CAT settings: a “Play it through the speakers” checkbox sits under the Icom RX-audio option — the same remembered switch as the consoles speaker button, applied immediately.",
"Icom network audio: “Talk to radio” now works over the LAN too — live microphone straight to the rig, PTT included. With RX audio and a headset, OpsLog is a complete remote station: hear, talk, key CW and log over one network link.", "Icom network audio: “Talk to radio” now works over the LAN too — live microphone straight to the rig, PTT included. With RX audio and a headset, OpsLog is a complete remote station: hear, talk, key CW and log over one network link.",
"Icom console: the SUB display shows the sub receivers frequency at all times (it was blank until split), and engaging split copies the mode to the TX VFO so it matches the main." "Icom console: the SUB display shows the sub receivers frequency at all times (it was blank until split), and engaging split copies the mode to the TX VFO so it matches the main.",
"Icom network audio: the stream now opens regardless of the speaker choice — speakers-off (or a failed output device) was silently disabling the whole stream: no audio session, no recordings, no voice keyer, despite the RX-audio option being ticked."
], ],
"fr": [ "fr": [
"Console Elecraft : le S-mètre est calibré sur un vrai K3 — S9 et les +dB correspondent désormais à laffichage de la radio (il lisait environ deux points S trop bas).", "Console Elecraft : le S-mètre est calibré sur un vrai K3 — S9 et les +dB correspondent désormais à laffichage de la radio (il lisait environ deux points S trop bas).",
@@ -52,7 +53,8 @@
"Console Icom : un bouton haut-parleur à côté de ON/OFF bascule l’écoute du RX audio réseau depuis la console — fini laller-retour dans Réglages → Audio ; enregistrements et voice keyer continuent de fonctionner, et le choix est mémorisé.", "Console Icom : un bouton haut-parleur à côté de ON/OFF bascule l’écoute du RX audio réseau depuis la console — fini laller-retour dans Réglages → Audio ; enregistrements et voice keyer continuent de fonctionner, et le choix est mémorisé.",
"Réglages CAT : une case « Écouter dans les enceintes » sous loption RX audio Icom — le même interrupteur mémorisé que le bouton haut-parleur de la console, appliqué immédiatement.", "Réglages CAT : une case « Écouter dans les enceintes » sous loption RX audio Icom — le même interrupteur mémorisé que le bouton haut-parleur de la console, appliqué immédiatement.",
"Audio réseau Icom : « Talk to radio » fonctionne aussi par le LAN — micro en direct vers la radio, PTT compris. Avec le RX audio et un casque, OpsLog devient une station remote complète : écouter, parler, manipuler la CW et loguer sur un seul lien réseau.", "Audio réseau Icom : « Talk to radio » fonctionne aussi par le LAN — micro en direct vers la radio, PTT compris. Avec le RX audio et un casque, OpsLog devient une station remote complète : écouter, parler, manipuler la CW et loguer sur un seul lien réseau.",
"Console Icom : laffichage SUB montre la fréquence du sub receiver en permanence (il restait vide hors split), et activer le split copie le mode sur le VFO TX pour quil suive le main." "Console Icom : laffichage SUB montre la fréquence du sub receiver en permanence (il restait vide hors split), et activer le split copie le mode sur le VFO TX pour quil suive le main.",
"Audio réseau Icom : le flux souvre désormais indépendamment du choix d’écoute — enceintes coupées (ou périphérique de sortie en échec) désactivait silencieusement tout le flux : pas de session audio, ni enregistrements, ni voice keyer, malgré la case RX audio cochée."
] ]
}, },
{ {