From b25efabab8535deabb1be7ffce37f63c38ea7045 Mon Sep 17 00:00:00 2001 From: rouggy Date: Fri, 31 Jul 2026 00:12:51 +0200 Subject: [PATCH] fix: check the configured capture device still exists before recording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third empty recording, same station, and the sequence was as plain as it gets: type the call, click record, log the QSO. The device opened and never streamed. Endpoint ids are what gets stored, and a DAX channel that is reconfigured, disabled or recreated comes back with a DIFFERENT id. The stale one opens without complaint on some drivers and simply never delivers — indistinguishable from a quiet band until the file turns out to be empty. The recorder now checks the id against the current endpoint list when it starts, which takes milliseconds, and says outright that the configured input is gone — on screen, not only in the log. If it IS still there, the answer is equally useful: the device exists and the fault is upstream, in whatever should be feeding it. --- internal/audio/recorder.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/audio/recorder.go b/internal/audio/recorder.go index 402af36..d75c89f 100644 --- a/internal/audio/recorder.go +++ b/internal/audio/recorder.go @@ -130,6 +130,30 @@ func (r *Recorder) Start(fromDev, micDev string, prerollSec int) error { if prerollSec < 0 { prerollSec = 0 } + // Does the configured endpoint still EXIST? + // + // Endpoint ids are stored, and a DAX channel that is reconfigured, disabled + // or removed comes back with a different id. The old one then opens without + // complaint on some drivers and simply never streams — which is + // indistinguishable from a quiet band until the recording turns out empty. + // Checking the list takes milliseconds and answers it outright. + if devs, derr := ListInputDevices(); derr == nil { + known := func(id string) bool { + for _, d := range devs { + if d.ID == id { + return true + } + } + return false + } + if fromDev != "" && !known(fromDev) { + LogSink("recorder: the configured radio input no longer exists (%s) — re-select it in Settings → Audio", fromDev) + AlertSink("The configured radio audio input no longer exists — re-select it in Settings") + } + if micDev != "" && micDev != fromDev && !known(micDev) { + LogSink("recorder: the configured microphone no longer exists (%s) — re-select it in Settings → Audio", micDev) + } + } r.prerollSamples = prerollSec * sampleRate r.twoSrc = micDev != "" && micDev != fromDev r.stopCh = make(chan struct{})