add a tone test mode that bypasses the soundcard

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>
This commit is contained in:
Brandon McGinty
2026-08-20 14:42:52 -04:00
co-authored by Claude Opus 5
parent 17a4662c6c
commit ecca0a63ed
6 changed files with 354 additions and 14 deletions
+6
View File
@@ -88,6 +88,9 @@ func main() {
jitterBuffer := flag.Int("jitter-buffer", 40, "incoming per-user audio buffer in ms (0, 20, 40, or 60)")
profile := flag.Bool("profile", false, "add http server to serve profiles")
noiseSuppressionEnabled := flag.Bool("noise-suppression", false, "enable noise suppression for microphone input")
autoTransmit := flag.Bool("auto-transmit", false, "start transmitting immediately on connect")
toneTest := flag.Bool("tone-test", false, "send a 440 Hz test tone instead of microphone (bypasses soundcard)")
toneTestOutput := flag.String("tone-out", "incoming.pcm", "file to save incoming audio to in tone-test mode")
tcpOnly := flag.Bool("tcp", false, "disable UDP, force audio through TCP tunnel")
logLevel := flag.String("log", "warn", "log level: debug, info, warn, error")
logFile := flag.String("logfile", "", "write logs to this file (logging is disabled when omitted)")
@@ -194,6 +197,9 @@ func main() {
Config: gumble.NewConfig(),
UserConfig: userConfig,
Address: *server,
AutoTransmit: *autoTransmit,
ToneTest: *toneTest,
ToneTestOutput: *toneTestOutput,
MutedChannels: make(map[uint32]bool),
NoiseSuppressor: noise.NewSuppressor(),
}