fix: say why playing a recording on the air did nothing

"I click play and nothing happens" is what an operator sees when a function
returns an error into a promise the interface swallows. Every refusal in the
playback path is now logged as well as returned, and each names its own cause —
audio not initialised, the take still running, the take empty, the device
rejecting the file.

One of those was not even checked: playing back needs an OUTPUT device INTO the
radio, which is a different setting from the recorder's input and is very likely
unset on a station that has only ever recorded. It now refuses with that
sentence instead of failing somewhere inside the player.
This commit is contained in:
2026-07-30 23:27:30 +02:00
parent 5a4ad800b3
commit f4956a63bb
2 changed files with 22 additions and 3 deletions
+18 -1
View File
@@ -7710,16 +7710,32 @@ func (a *App) QSOAudioResume() bool {
// loop. Stopping is the operator's statement that the take is finished, and it
// is one click they have already made.
func (a *App) QSOAudioPlayOnAir() error {
// Every refusal below is LOGGED as well as returned. "I click play and
// nothing happens" is what an operator sees when a function returns an error
// into a promise the interface swallowed — and the difference between "no
// output device configured" and "the take was empty" cannot be guessed from
// the outside.
if a.qsoRec == nil || a.audioMgr == nil {
applog.Printf("qso-rec: play refused — audio subsystem not initialised")
return fmt.Errorf("audio not initialized")
}
if !a.qsoRec.Paused() {
applog.Printf("qso-rec: play refused — the recording is still running (stop it first)")
return fmt.Errorf("stop the recording before playing it on the air")
}
pcm, err := a.qsoRec.PeekQSO()
if err != nil {
applog.Printf("qso-rec: play refused — %v", err)
return err
}
cfgEarly, _ := a.GetAudioSettings()
if strings.TrimSpace(cfgEarly.ToRadio) == "" {
// The recorder needs an INPUT from the radio; playing back needs an
// OUTPUT into it, which is a different device and may well be unset on a
// station that only ever recorded.
applog.Printf("qso-rec: play refused — no output device to the radio configured (Settings → Audio)")
return fmt.Errorf("no audio output to the radio is configured — set it in Settings → Audio")
}
// A plain WAV in the data dir, overwritten each time: the player takes a
// path, and MP3 encoding would add seconds to something the operator is
// waiting on with the transmitter keyed.
@@ -7728,7 +7744,7 @@ func (a *App) QSOAudioPlayOnAir() error {
return fmt.Errorf("prepare playback: %w", err)
}
cfg, _ := a.GetAudioSettings()
cfg := cfgEarly
if err := a.pttKey(cfg); err != nil {
applog.Printf("qso-rec: PTT on failed before playback: %v", err)
// Keep going — the audio still reaches the rig and the operator may use VOX.
@@ -7738,6 +7754,7 @@ func (a *App) QSOAudioPlayOnAir() error {
a.pttMu.Unlock()
}
if err := a.audioMgr.Play(cfg.ToRadio, path, cfg.TXGain); err != nil {
applog.Printf("qso-rec: playback on %q failed: %v", cfg.ToRadio, err)
a.pttMu.Lock()
keyed := a.dvkPttKeyed
gen := a.pttGen