feat(icom): listening to the network audio is a remembered choice

The RX stream and the speakers were welded together: every reconnect and
every launch restarted the monitor, so an operator sitting in the room with
the radio could not have the stream (which the recorder and the voice keyer
need) without also hearing it twice. Stop listening now persists, the Listen
button turns it back on, and reconnects respect the choice.
This commit is contained in:
2026-08-29 19:42:18 +02:00
parent 13434ca36c
commit c878742e50
2 changed files with 15 additions and 3 deletions
+11 -1
View File
@@ -159,6 +159,7 @@ const (
keyCATIcomNetUser = "cat.icom.net.user" // Icom network: Network User1 ID
keyCATIcomNetPass = "cat.icom.net.pass" // Icom network: Network User1 password
keyCATIcomNetAudio = "cat.icom.net.audio" // Icom network: stream RX audio on 50003 (experimental)
keyAudioMonitorOn = "audio.monitor.on" // play the network RX audio through the Listening device (the stream itself stays open for the recorder either way)
keyCATTCIHost = "cat.tci.host" // TCI host (Expert Electronics SunSDR / ExpertSDR2)
keyCATTCIPort = "cat.tci.port" // TCI WebSocket port (default 40001)
keyCATTCISpots = "cat.tci.spots" // push cluster spots to the TCI panorama
@@ -10690,6 +10691,7 @@ func (a *App) AudioStartMonitor() error {
// The result was audio chopped to pieces the moment the operator toggled
// Listening off and on while connected to a network Icom.
if cs, err := a.GetCATSettings(); err == nil && cs.Enabled && cs.Backend == "icom-net" && cs.IcomNetAudio {
a.setSetting(keyAudioMonitorOn, "1")
applog.Printf("audio: RX monitor start (network sink only → listen=%q)", cfg.ListeningDevice)
return a.audioMgr.StartMonitorSink(cfg.ListeningDevice)
}
@@ -10700,6 +10702,7 @@ func (a *App) AudioStartMonitor() error {
// AudioStopMonitor stops the RX monitor passthrough.
func (a *App) AudioStopMonitor() {
a.setSetting(keyAudioMonitorOn, "0")
if a.audioMgr != nil {
a.audioMgr.StopMonitor()
applog.Printf("audio: RX monitor stopped")
@@ -15590,7 +15593,14 @@ func (a *App) reloadCAT() {
// verification (see icomaudio.go) — hence experimental + opt-in.
acfg, _ := a.GetAudioSettings()
a.audioMgr.StopMonitor() // clear any prior monitor/sink so a re-save restarts cleanly
if err := a.audioMgr.StartMonitorSink(acfg.ListeningDevice); err != nil {
// 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: cannot start output sink: %v", err)
} else {
codec := audio.NewPCM16Codec()