Add -tone-test to transmit a generated 440 Hz Opus tone and save incoming audio to the file named by -tone-out. Diagnosing an audio problem previously required a working capture and playback device, which is exactly what is in question. This mode opens no OpenAL device at all, so the network and codec path can be tested on a machine with no sound hardware. Open the capture file before starting the generator. Starting transmission first left a tone goroutine running with nowhere to write when the path was unusable. Refuse file playback while in tone test mode, and ignore the microphone volume keys. Both operate on a stream that does not exist here. Stop the generator and detach the file saver on disconnect. A reconnect otherwise attached a second saver to the same file. Add -auto-transmit to key the microphone as soon as the connection is up. Useful for a bot or a monitoring client that should never need a keypress. It runs from both the connect event and the point where the audio stream is created, because the server's welcome arrives before the stream exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
2.1 KiB
Go
69 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// Regression: tone transmission was started before opening its output file,
|
|
// so a creation error left audio transmission running without cleanup.
|
|
// Regression: tone test transmitted immediately, preventing the configured
|
|
// talk key from controlling it.
|
|
func TestToneTestRequiresAutoTransmit(t *testing.T) {
|
|
if (&Barnard{ToneTest: true}).toneTestAutoTransmit() {
|
|
t.Fatal("tone test started without auto-transmit")
|
|
}
|
|
if !(&Barnard{ToneTest: true, AutoTransmit: true}).toneTestAutoTransmit() {
|
|
t.Fatal("tone test did not auto-transmit")
|
|
}
|
|
}
|
|
|
|
func TestNewAudioFileSaverReportsUnavailableOutputPath(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "missing", "tone.pcm")
|
|
if saver, err := NewAudioFileSaver(path); err == nil || saver != nil {
|
|
t.Fatalf("got saver=%v err=%v", saver, err)
|
|
}
|
|
}
|
|
|
|
func TestNewAudioFileSaverDoesNotOverwriteExistingOutput(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "tone.pcm")
|
|
if err := os.WriteFile(path, []byte("existing"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if saver, err := NewAudioFileSaver(path); err == nil || saver != nil {
|
|
t.Fatalf("got saver=%v err=%v", saver, err)
|
|
}
|
|
contents, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(contents) != "existing" {
|
|
t.Fatalf("output was overwritten: %q", contents)
|
|
}
|
|
}
|
|
|
|
type testDetacher struct{ detached bool }
|
|
|
|
func (d *testDetacher) Detach() { d.detached = true }
|
|
|
|
// Regression: reconnecting tone-test mode kept prior savers attached to the
|
|
// shared audio listener list, causing callbacks to write to closed files.
|
|
func TestCleanupToneTestAudioDetachesSaver(t *testing.T) {
|
|
saver, err := NewAudioFileSaver(filepath.Join(t.TempDir(), "tone.pcm"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
detacher := &testDetacher{}
|
|
b := &Barnard{toneTestSaver: saver, toneTestSaverDetach: detacher}
|
|
|
|
b.cleanupToneTestAudio()
|
|
if !detacher.detached {
|
|
t.Fatal("tone saver listener was not detached")
|
|
}
|
|
if b.toneTestSaver != nil || b.toneTestSaverDetach != nil {
|
|
t.Fatal("tone saver cleanup retained connection state")
|
|
}
|
|
b.cleanupToneTestAudio()
|
|
}
|