Updated how mute and deafen for self works, more similar to official client behavior.

This commit is contained in:
Storm Dragon
2026-09-05 22:11:03 -04:00
parent cf9746c8de
commit 97e0dc9281
5 changed files with 111 additions and 23 deletions
+22 -6
View File
@@ -32,12 +32,13 @@ type Barnard struct {
Address string Address string
TLSConfig tls.Config TLSConfig tls.Config
Stream *gumbleopenal.Stream Stream *gumbleopenal.Stream
connectionMutex sync.RWMutex connectionMutex sync.RWMutex
Tx bool Tx bool
AutoTransmit bool // auto-start transmission on connect AutoTransmit bool // auto-start transmission on connect
Connected bool Connected bool
stateMutex sync.RWMutex unmuteOnUndeafen bool
stateMutex sync.RWMutex
Ui *uiterm.Ui Ui *uiterm.Ui
UiOutput uiterm.Textview UiOutput uiterm.Textview
@@ -213,6 +214,21 @@ func (b *Barnard) isConnected() bool {
func (b *Barnard) setConnected(connected bool) { func (b *Barnard) setConnected(connected bool) {
b.stateMutex.Lock() b.stateMutex.Lock()
b.Connected = connected b.Connected = connected
if !connected {
b.unmuteOnUndeafen = false
}
b.stateMutex.Unlock()
}
func (b *Barnard) shouldUnmuteOnUndeafen() bool {
b.stateMutex.RLock()
defer b.stateMutex.RUnlock()
return b.unmuteOnUndeafen
}
func (b *Barnard) setUnmuteOnUndeafen(unmute bool) {
b.stateMutex.Lock()
b.unmuteOnUndeafen = unmute
b.stateMutex.Unlock() b.stateMutex.Unlock()
} }
+33
View File
@@ -150,6 +150,39 @@ func TestTransmitDoesNotStartWhileSelfMuted(t *testing.T) {
} }
} }
func TestSelfDeafenRestoresPriorMuteState(t *testing.T) {
tests := []struct {
name string
deafened bool
currentlyMuted bool
unmuteOnUndeafen bool
wantMuted bool
wantRememberUnmute bool
}{
{name: "deafen while unmuted", deafened: true, wantMuted: true, wantRememberUnmute: true},
{name: "deafen while already muted", deafened: true, currentlyMuted: true, wantMuted: true},
{name: "undeafen automatic mute", unmuteOnUndeafen: true},
{name: "undeafen prior mute", wantMuted: true},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
muted, rememberUnmute := selfDeafenTarget(test.deafened, test.currentlyMuted, test.unmuteOnUndeafen)
if muted != test.wantMuted || rememberUnmute != test.wantRememberUnmute {
t.Fatalf("got muted=%t rememberUnmute=%t; want muted=%t rememberUnmute=%t", muted, rememberUnmute, test.wantMuted, test.wantRememberUnmute)
}
})
}
}
func TestDisconnectForgetsAutomaticDeafenMute(t *testing.T) {
b := &Barnard{}
b.setUnmuteOnUndeafen(true)
b.setConnected(false)
if b.shouldUnmuteOnUndeafen() {
t.Fatal("disconnect retained automatic deafen mute state")
}
}
func TestConcurrentSelectedUserAccess(t *testing.T) { func TestConcurrentSelectedUserAccess(t *testing.T) {
b := &Barnard{} b := &Barnard{}
user := &gumble.User{Session: 1} user := &gumble.User{Session: 1}
+8
View File
@@ -76,10 +76,18 @@ mutedeafen() {
[[ $notify ]] && notify "You muted and deafened yourself." [[ $notify ]] && notify "You muted and deafened yourself."
} }
deafen() {
[[ $notify ]] && notify "You deafened yourself."
}
muteundeafen() { muteundeafen() {
[[ $notify ]] && notify "You undeafened yourself. Your microphone remains muted." [[ $notify ]] && notify "You undeafened yourself. Your microphone remains muted."
} }
unmuteundeafen() {
[[ $notify ]] && notify "You unmuted and undeafened yourself."
}
msg() { msg() {
[[ $sound ]] && play -n synth .3 sin 1290:1490 sin 1494:1294 remix - norm -8 [[ $sound ]] && play -n synth .3 sin 1290:1490 sin 1494:1294 remix - norm -8
[[ $notify ]] && notify "$1 from $2: $3" [[ $notify ]] && notify "$1 from $2: $3"
+16 -11
View File
@@ -9,12 +9,17 @@ import (
) )
func TestSetSelfMutedAndDeafenedWritesOneCombinedState(t *testing.T) { func TestSetSelfMutedAndDeafenedWritesOneCombinedState(t *testing.T) {
for _, deafened := range []bool{true, false} { tests := []struct {
name := "undeafen" name string
if deafened { muted bool
name = "deafen" deafened bool
} }{
t.Run(name, func(t *testing.T) { {name: "deafen", muted: true, deafened: true},
{name: "undeafen and remain muted", muted: true},
{name: "undeafen and unmute"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
local, remote := net.Pipe() local, remote := net.Pipe()
defer local.Close() defer local.Close()
defer remote.Close() defer remote.Close()
@@ -23,7 +28,7 @@ func TestSetSelfMutedAndDeafenedWritesOneCombinedState(t *testing.T) {
user := &User{Session: 7, client: client} user := &User{Session: 7, client: client}
written := make(chan struct{}) written := make(chan struct{})
go func() { go func() {
user.SetSelfMutedAndDeafened(true, deafened) user.SetSelfMutedAndDeafened(test.muted, test.deafened)
close(written) close(written)
}() }()
@@ -38,11 +43,11 @@ func TestSetSelfMutedAndDeafenedWritesOneCombinedState(t *testing.T) {
if err := proto.Unmarshal(data, &state); err != nil { if err := proto.Unmarshal(data, &state); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if state.SelfMute == nil || !*state.SelfMute { if state.SelfMute == nil || *state.SelfMute != test.muted {
t.Fatalf("self mute = %v, want true", state.SelfMute) t.Fatalf("self mute = %v, want %v", state.SelfMute, test.muted)
} }
if state.SelfDeaf == nil || *state.SelfDeaf != deafened { if state.SelfDeaf == nil || *state.SelfDeaf != test.deafened {
t.Fatalf("self deafen = %v, want %v", state.SelfDeaf, deafened) t.Fatalf("self deafen = %v, want %v", state.SelfDeaf, test.deafened)
} }
<-written <-written
}) })
+32 -6
View File
@@ -233,6 +233,13 @@ func (b *Barnard) setSelfMute(muted bool) {
b.UpdateGeneralStatus("cannot change self mute while disconnected", true) b.UpdateGeneralStatus("cannot change self mute while disconnected", true)
return return
} }
if !muted && b.selfDeafened() {
b.setUnmuteOnUndeafen(false)
b.Client.Self.SetSelfMutedAndDeafened(false, false)
b.Notify("unmuteundeafen", "me", "")
b.AddOutputLine("You unmuted and undeafened yourself")
return
}
if b.selfMuted() == muted { if b.selfMuted() == muted {
return return
} }
@@ -272,17 +279,36 @@ func (b *Barnard) setSelfDeafen(deafened bool) {
if b.selfDeafened() == deafened { if b.selfDeafened() == deafened {
return return
} }
if b.isTransmitting() { if deafened && b.isTransmitting() {
b.StopTransmission() b.StopTransmission()
} }
b.Client.Self.SetSelfMutedAndDeafened(true, deafened) muted, unmuteOnUndeafen := selfDeafenTarget(deafened, b.selfMuted(), b.shouldUnmuteOnUndeafen())
b.setUnmuteOnUndeafen(unmuteOnUndeafen)
b.Client.Self.SetSelfMutedAndDeafened(muted, deafened)
if deafened { if deafened {
b.Notify("mutedeafen", "me", "") if unmuteOnUndeafen {
b.AddOutputLine("You muted and deafened yourself") b.Notify("mutedeafen", "me", "")
b.AddOutputLine("You muted and deafened yourself")
} else {
b.Notify("deafen", "me", "")
b.AddOutputLine("You deafened yourself")
}
return return
} }
b.Notify("muteundeafen", "me", "") if muted {
b.AddOutputLine("You undeafened yourself; microphone remains muted") b.Notify("muteundeafen", "me", "")
b.AddOutputLine("You undeafened yourself; microphone remains muted")
} else {
b.Notify("unmuteundeafen", "me", "")
b.AddOutputLine("You unmuted and undeafened yourself")
}
}
func selfDeafenTarget(deafened, currentlyMuted, unmuteOnUndeafen bool) (muted, rememberUnmute bool) {
if deafened {
return true, !currentlyMuted
}
return !unmuteOnUndeafen, false
} }
func (b *Barnard) toggleSelfDeafen() { func (b *Barnard) toggleSelfDeafen() {