Add F12 hotkey to toggle microphone AGC
Automatic gain control was always on with no way to turn it off. Toggle it with F12, the /agc command, or the agc FIFO command, and persist the choice in the configuration file the same way noise suppression does. AgcEnabled defaults to true so existing setups keep their current behavior, and the saved value is applied to the stream on connect. The enabled flag becomes an atomic.Bool because the capture goroutine reads it while the UI goroutine writes it, and the lazily created right channel AGC now inherits the left channel's state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
132df6863a
commit
4393739ffa
8 files changed
+156
-25
No files matched your search
@@ -21,4 +21,5 @@ type Hotkeys struct {
|
||||
ScrollToBottom *uiterm.Key
|
||||
AdminMenu *uiterm.Key
|
||||
NoiseSuppressionToggle *uiterm.Key
|
||||
AGCToggle *uiterm.Key
|
||||
}
|
||||
@@ -31,6 +31,7 @@ type exportableConfig struct {
|
||||
Username *string
|
||||
NotifyCommand *string
|
||||
NoiseSuppressionEnabled *bool
|
||||
AGCEnabled *bool
|
||||
Certificate *string
|
||||
RecordingFormat *string
|
||||
RecordingDirectory *string
|
||||
@@ -109,6 +110,7 @@ func (c *Config) LoadConfig() {
|
||||
ScrollToBottom: key(uiterm.KeyEnd),
|
||||
AdminMenu: key(uiterm.KeyF11),
|
||||
NoiseSuppressionToggle: key(uiterm.KeyF9),
|
||||
AGCToggle: key(uiterm.KeyF12),
|
||||
}
|
||||
if fileExists(c.fn) {
|
||||
var data []byte
|
||||
@@ -155,6 +157,11 @@ func (c *Config) LoadConfig() {
|
||||
enabled := false
|
||||
jc.NoiseSuppressionEnabled = &enabled
|
||||
}
|
||||
if c.config.AGCEnabled == nil {
|
||||
// AGC has always been active for the microphone, so keep it on by default.
|
||||
enabled := true
|
||||
jc.AGCEnabled = &enabled
|
||||
}
|
||||
if c.config.Certificate == nil {
|
||||
cert := string("")
|
||||
jc.Certificate = &cert
|
||||
@@ -190,6 +197,7 @@ func (c *Config) ensureHotkeys() {
|
||||
ScrollToBottom: key(uiterm.KeyEnd),
|
||||
AdminMenu: key(uiterm.KeyF11),
|
||||
NoiseSuppressionToggle: key(uiterm.KeyF9),
|
||||
AGCToggle: key(uiterm.KeyF12),
|
||||
}
|
||||
hotkeys := c.config.Hotkeys
|
||||
if hotkeys.Talk == nil {
|
||||
@@ -240,6 +248,9 @@ func (c *Config) ensureHotkeys() {
|
||||
if hotkeys.NoiseSuppressionToggle == nil {
|
||||
hotkeys.NoiseSuppressionToggle = defaults.NoiseSuppressionToggle
|
||||
}
|
||||
if hotkeys.AGCToggle == nil {
|
||||
hotkeys.AGCToggle = defaults.AGCToggle
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) findServer(address string) *server {
|
||||
@@ -365,6 +376,22 @@ func (c *Config) SetNoiseSuppressionEnabled(enabled bool) error {
|
||||
return c.saveConfigLocked()
|
||||
}
|
||||
|
||||
func (c *Config) GetAGCEnabled() bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.config.AGCEnabled == nil {
|
||||
return true
|
||||
}
|
||||
return *c.config.AGCEnabled
|
||||
}
|
||||
|
||||
func (c *Config) SetAGCEnabled(enabled bool) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.config.AGCEnabled = &enabled
|
||||
return c.saveConfigLocked()
|
||||
}
|
||||
|
||||
func (c *Config) GetRecordingFormat() string {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -74,6 +74,35 @@ func TestConfigBackfillsRecordingDefaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAGCDefaultsOnAndPersists(t *testing.T) {
|
||||
configPath := filepath.Join(t.TempDir(), "barnard.toml")
|
||||
if err := os.WriteFile(configPath, []byte("[hotkeys]\ntalk = \"f1\"\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cfg := NewConfig(&configPath)
|
||||
if !cfg.GetAGCEnabled() {
|
||||
t.Fatal("expected AGC to default to enabled")
|
||||
}
|
||||
if cfg.GetHotkeys().AGCToggle == nil {
|
||||
t.Fatal("expected AGC toggle hotkey to be backfilled")
|
||||
}
|
||||
if got := *cfg.GetHotkeys().AGCToggle; got != uiterm.KeyF12 {
|
||||
t.Fatalf("expected AGC toggle f12, got %s", got)
|
||||
}
|
||||
|
||||
if err := cfg.SetAGCEnabled(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reloaded := NewConfig(&configPath)
|
||||
if reloaded.GetAGCEnabled() {
|
||||
t.Fatal("expected disabled AGC setting to persist")
|
||||
}
|
||||
if got := *reloaded.GetHotkeys().AGCToggle; got != uiterm.KeyF12 {
|
||||
t.Fatalf("expected saved AGC toggle to reload as f12, got %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Regression: malformed and IPv6 addresses were split at every colon and
|
||||
// could panic while merely reading a saved user preference.
|
||||
func TestMakeHostPortHandlesIPv6AndMalformedAddress(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user