This commit is contained in:
2026-06-15 23:45:14 +02:00
parent 29fd832bcd
commit 22e3bb4a18
32 changed files with 2531 additions and 362 deletions
+18
View File
@@ -5,11 +5,26 @@ package audio
import (
"encoding/binary"
"fmt"
"runtime/debug"
"strings"
"sync"
"time"
)
// LogSink receives audio-subsystem diagnostics (set to applog.Printf at startup).
// Defaults to a no-op so the package is usable without wiring.
var LogSink = func(string, ...any) {}
// recoverGoroutine turns a panic in a long-running audio goroutine into a logged
// event with a stack trace instead of a silent process-killing crash. (It can't
// catch a hard Windows access violation from the WASAPI layer — those are fatal
// — but it catches any Go-level panic in capture/mix.)
func recoverGoroutine(what string) {
if r := recover(); r != nil {
LogSink("audio: PANIC in %s: %v\n%s", what, r, debug.Stack())
}
}
// Recorder continuously captures audio into a rolling pre-roll buffer so a QSO
// recording can begin a few seconds BEFORE the operator entered the callsign.
// It optionally mixes two sources (the rig RX "From Radio" + your mic) into a
@@ -108,6 +123,7 @@ func (r *Recorder) Start(fromDev, micDev string, prerollSec int) error {
r.wg.Add(1)
go func() {
defer r.wg.Done()
defer recoverGoroutine("recorder capture (radio)")
_ = captureStream(fromDev, stop, func(chunk []byte) {
s := bytesToInt16(chunk)
r.srcMu.Lock()
@@ -119,6 +135,7 @@ func (r *Recorder) Start(fromDev, micDev string, prerollSec int) error {
r.wg.Add(1)
go func() {
defer r.wg.Done()
defer recoverGoroutine("recorder capture (mic)")
_ = captureStream(micDev, stop, func(chunk []byte) {
s := bytesToInt16(chunk)
r.srcMu.Lock()
@@ -132,6 +149,7 @@ func (r *Recorder) Start(fromDev, micDev string, prerollSec int) error {
r.wg.Add(1)
go func() {
defer r.wg.Done()
defer recoverGoroutine("recorder mixer")
t := time.NewTicker(40 * time.Millisecond)
defer t.Stop()
for {