Restore transmit state after unmute/deafen. Send proper notifications to other users.

This commit is contained in:
Storm Dragon
2026-09-06 01:04:10 -04:00
parent 97e0dc9281
commit 2b5fe91d6c
5 changed files with 276 additions and 16 deletions
+100
View File
@@ -161,6 +161,7 @@ func (b *Barnard) OnConnect(e *gumble.ConnectEvent) {
b.MutedChannels = make(map[uint32]bool)
b.MutedChannelsMutex.Unlock()
b.userChannels = make(map[uint32]*gumble.Channel)
b.userAudioStates = make(map[uint32]userAudioState)
b.RecordingMutex.Lock()
b.recordingAllowed = nil
b.recordingStarting = false
@@ -182,6 +183,7 @@ func (b *Barnard) OnConnect(e *gumble.ConnectEvent) {
for _, u := range users {
b.UserConfig.UpdateUser(u)
b.rememberUserChannel(u)
b.rememberUserAudioState(u)
}
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.Client.Self.Channel.Name))
@@ -339,6 +341,7 @@ func (b *Barnard) isPublicTextMessage(e *gumble.TextMessageEvent) bool {
func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
notification, hasNotification := b.userChangeNotification(e)
audioNotification, hasAudioNotification := b.userAudioChangeNotification(e)
if e.User != nil {
b.UserConfig.UpdateUser(e.User)
@@ -366,6 +369,11 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
b.Notify(notification.event, notification.who, notification.what)
b.AddOutputLine(notification.line)
}
if hasAudioNotification {
b.Notify(audioNotification.event, audioNotification.who, audioNotification.what)
b.AddOutputLine(audioNotification.line)
}
b.restoreTransmissionAfterUndeafen(e)
if e.Type.Has(gumble.UserChangeChannel) && e.User == b.Client.Self {
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.User.Channel.Name))
}
@@ -383,6 +391,7 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
b.AddOutputLine(formatUserStats(e.User))
}
b.updateUserChannel(e)
b.updateUserAudioState(e)
b.postUI(func() {
b.RebuildUserChannelTreePreservingSelection()
b.Ui.Refresh()
@@ -396,6 +405,11 @@ type userChangeNotification struct {
line string
}
type userAudioState struct {
selfMuted bool
selfDeafened bool
}
func (b *Barnard) userChangeNotification(e *gumble.UserChangeEvent) (userChangeNotification, bool) {
if e == nil || e.User == nil || b.Client == nil || b.Client.Self == nil || b.Client.Self.Channel == nil {
return userChangeNotification{}, false
@@ -426,6 +440,68 @@ func (b *Barnard) userChangeNotification(e *gumble.UserChangeEvent) (userChangeN
return userChangeNotification{}, false
}
func (b *Barnard) userAudioChangeNotification(e *gumble.UserChangeEvent) (userChangeNotification, bool) {
if e == nil || e.User == nil || !e.Type.Has(gumble.UserChangeAudio) || b.Client == nil || b.Client.Self == nil || b.Client.Self.Channel == nil {
return userChangeNotification{}, false
}
// Barnard announces its own hotkey actions immediately. The protocol echo
// is only needed to announce state changes made by other users.
if e.User.Session == b.Client.Self.Session {
return userChangeNotification{}, false
}
previous, known := b.userAudioStates[e.User.Session]
if !known || !sameChannel(e.User.Channel, b.Client.Self.Channel) {
return userChangeNotification{}, false
}
muteEvent, muteVerb := "", ""
if previous.selfMuted != e.User.SelfMuted {
if e.User.SelfMuted {
muteEvent, muteVerb = "mute", "muted"
} else {
muteEvent, muteVerb = "unmute", "unmuted"
}
}
deafenEvent, deafenVerb := "", ""
if previous.selfDeafened != e.User.SelfDeafened {
if e.User.SelfDeafened {
deafenEvent, deafenVerb = "deafen", "deafened"
} else {
deafenEvent, deafenVerb = "undeafen", "undeafened"
}
}
event := muteEvent + deafenEvent
verbs := make([]string, 0, 2)
if muteVerb != "" {
verbs = append(verbs, muteVerb)
}
if deafenVerb != "" {
verbs = append(verbs, deafenVerb)
}
if event == "" {
return userChangeNotification{}, false
}
verb := strings.Join(verbs, " and ")
return userChangeNotification{
event: event,
who: e.User.Name,
what: e.User.Channel.Name,
line: fmt.Sprintf("%s %s", e.User.Name, verb),
}, true
}
func (b *Barnard) restoreTransmissionAfterUndeafen(e *gumble.UserChangeEvent) {
if e == nil || e.User == nil || !e.Type.Has(gumble.UserChangeAudio) || b.Client == nil || b.Client.Self == nil {
return
}
if e.User.Session != b.Client.Self.Session || e.User.SelfDeafened || !b.shouldTransmitOnUndeafen() {
return
}
b.setTransmitOnUndeafen(false)
b.postUI(func() { b.setTransmit(nil, 1) })
}
func buildUserChangeNotification(event string, verb string, user *gumble.User, eventChannel *gumble.Channel, currentChannel *gumble.Channel) (userChangeNotification, bool) {
if !sameChannel(eventChannel, currentChannel) {
return userChangeNotification{}, false
@@ -472,6 +548,30 @@ func (b *Barnard) updateUserChannel(e *gumble.UserChangeEvent) {
b.rememberUserChannel(e.User)
}
func (b *Barnard) rememberUserAudioState(user *gumble.User) {
if user == nil {
return
}
if b.userAudioStates == nil {
b.userAudioStates = make(map[uint32]userAudioState)
}
b.userAudioStates[user.Session] = userAudioState{
selfMuted: user.SelfMuted,
selfDeafened: user.SelfDeafened,
}
}
func (b *Barnard) updateUserAudioState(e *gumble.UserChangeEvent) {
if e == nil || e.User == nil {
return
}
if e.Type.Has(gumble.UserChangeDisconnected) {
delete(b.userAudioStates, e.User.Session)
return
}
b.rememberUserAudioState(e.User)
}
func (b *Barnard) OnChannelChange(e *gumble.ChannelChangeEvent) {
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.Channel.Name))
if e.Type.Has(gumble.ChannelChangeDescription) {