Added mute option. It can work per user or per channel, so covers deafen functionality too.

This commit is contained in:
Storm Dragon 2025-01-16 13:36:46 -05:00
parent 46d0cbf8f5
commit a5c0e7a71c
5 changed files with 551 additions and 499 deletions

View File

@ -8,6 +8,7 @@ type Hotkeys struct {
Talk *uiterm.Key Talk *uiterm.Key
VolumeDown *uiterm.Key VolumeDown *uiterm.Key
VolumeUp *uiterm.Key VolumeUp *uiterm.Key
MuteToggle *uiterm.Key
Exit *uiterm.Key Exit *uiterm.Key
ToggleTimestamps *uiterm.Key ToggleTimestamps *uiterm.Key
SwitchViews *uiterm.Key SwitchViews *uiterm.Key

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"git.2mb.codes/~cmb/barnard/uiterm" "git.2mb.codes/~cmb/barnard/uiterm"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
// "encoding/yaml"
"git.2mb.codes/~cmb/barnard/gumble/gumble" "git.2mb.codes/~cmb/barnard/gumble/gumble"
"io/ioutil" "io/ioutil"
"os" "os"
@ -39,6 +38,7 @@ type eUser struct {
Username string Username string
Boost uint16 Boost uint16
Volume float32 Volume float32
LocallyMuted bool // Changed from Muted to LocallyMuted to match User struct
} }
func (c *Config) SaveConfig() { func (c *Config) SaveConfig() {
@ -68,6 +68,7 @@ func (c *Config) LoadConfig() {
Talk: key(uiterm.KeyF1), Talk: key(uiterm.KeyF1),
VolumeDown: key(uiterm.KeyF5), VolumeDown: key(uiterm.KeyF5),
VolumeUp: key(uiterm.KeyF6), VolumeUp: key(uiterm.KeyF6),
MuteToggle: key(uiterm.KeyF7), // Added mute toggle hotkey
Exit: key(uiterm.KeyF10), Exit: key(uiterm.KeyF10),
ToggleTimestamps: key(uiterm.KeyF3), ToggleTimestamps: key(uiterm.KeyF3),
SwitchViews: key(uiterm.KeyTab), SwitchViews: key(uiterm.KeyTab),
@ -82,9 +83,9 @@ func (c *Config) LoadConfig() {
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing \"%s\".\n%s\n", c.fn, err.Error()) fmt.Fprintf(os.Stderr, "Error parsing \"%s\".\n%s\n", c.fn, err.Error())
os.Exit(1) os.Exit(1)
} //panic }
} //if data }
} //if exists }
c.config = &jc c.config = &jc
if c.config.MicVolume == nil { if c.config.MicVolume == nil {
micvol := float32(1.0) micvol := float32(1.0)
@ -152,12 +153,20 @@ func (c *Config) findUser(address string, username string) *eUser {
Username: username, Username: username,
Boost: uint16(1), Boost: uint16(1),
Volume: 1.0, Volume: 1.0,
LocallyMuted: false, // Initialize local mute state
} }
s.Users = append(s.Users, t) s.Users = append(s.Users, t)
} }
return t return t
} }
func (c *Config) ToggleMute(u *gumble.User) {
j := c.findUser(u.GetClient().Config.Address, u.Name)
j.LocallyMuted = !j.LocallyMuted
u.LocallyMuted = j.LocallyMuted
c.SaveConfig()
}
func (c *Config) SetMicVolume(v float32) { func (c *Config) SetMicVolume(v float32) {
t := float32(v) t := float32(v)
c.config.MicVolume = &t c.config.MicVolume = &t
@ -195,6 +204,7 @@ func (c *Config) UpdateUser(u *gumble.User) {
j = c.findUser(uc.Config.Address, u.Name) j = c.findUser(uc.Config.Address, u.Name)
u.Boost = j.Boost u.Boost = j.Boost
u.Volume = j.Volume u.Volume = j.Volume
u.LocallyMuted = j.LocallyMuted // Update LocallyMuted state from config
if u.Boost < 1 { if u.Boost < 1 {
u.Boost = 1 u.Boost = 1
} }
@ -206,6 +216,7 @@ func (c *Config) UpdateConfig(u *gumble.User) {
j = c.findUser(u.GetClient().Config.Address, u.Name) j = c.findUser(u.GetClient().Config.Address, u.Name)
j.Boost = u.Boost j.Boost = u.Boost
j.Volume = u.Volume j.Volume = u.Volume
j.LocallyMuted = u.LocallyMuted // Save LocallyMuted state to config
} }
func NewConfig(fn *string) *Config { func NewConfig(fn *string) *Config {
@ -267,7 +278,6 @@ func Log(s string) {
func log(s string) { func log(s string) {
s += "\n" s += "\n"
// If the file doesn't exist, create it, or append to the file
f, err := os.OpenFile("log.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) f, err := os.OpenFile("log.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -31,6 +31,8 @@ type User struct {
PrioritySpeaker bool PrioritySpeaker bool
// Is the user recording audio? // Is the user recording audio?
Recording bool Recording bool
// Has the user been locally muted by the client?
LocallyMuted bool
// The user's comment. Contains the empty string if the user does not have a // The user's comment. Contains the empty string if the user does not have a
// comment, or if the comment needs to be requested. // comment, or if the comment needs to be requested.
@ -56,6 +58,11 @@ type User struct {
Volume float32 Volume float32
} }
// IsMuted returns true if the user is muted either server-side or locally
func (u *User) IsMuted() bool {
return u.Muted || u.LocallyMuted
}
func (u *User) GetClient() *Client { func (u *User) GetClient() *Client {
return u.client return u.client
} }

View File

@ -164,7 +164,13 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
go func(e *gumble.AudioStreamEvent) { go func(e *gumble.AudioStreamEvent) {
var source = openal.NewSource() var source = openal.NewSource()
e.User.AudioSource = &source e.User.AudioSource = &source
// Set initial gain based on volume and mute state
if e.User.LocallyMuted {
e.User.AudioSource.SetGain(0)
} else {
e.User.AudioSource.SetGain(e.User.Volume) e.User.AudioSource.SetGain(e.User.Volume)
}
bufferCount := e.Client.Config.Buffers bufferCount := e.Client.Config.Buffers
if bufferCount < 64 { if bufferCount < 64 {
@ -183,6 +189,11 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
var raw [maxBufferSize]byte var raw [maxBufferSize]byte
for packet := range e.C { for packet := range e.C {
// Skip processing if user is locally muted
if e.User.LocallyMuted {
continue
}
var boost uint16 = uint16(1) var boost uint16 = uint16(1)
samples := len(packet.AudioBuffer) samples := len(packet.AudioBuffer)
if samples > cap(raw)/2 { if samples > cap(raw)/2 {
@ -192,17 +203,13 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
boost = e.User.Boost boost = e.User.Boost
// Check if sample count suggests stereo data // Check if sample count suggests stereo data
// If it's not a multiple of 2, it must be mono
// If it's more than standard frameSize, it's likely stereo
isStereo := samples > gumble.AudioDefaultFrameSize && samples%2 == 0 isStereo := samples > gumble.AudioDefaultFrameSize && samples%2 == 0
format := openal.FormatMono16 format := openal.FormatMono16
if isStereo { if isStereo {
format = openal.FormatStereo16 format = openal.FormatStereo16
// Adjust samples to represent stereo frame count
samples = samples / 2 samples = samples / 2
} }
// Process samples
rawPtr := 0 rawPtr := 0
if isStereo { if isStereo {
// Process stereo samples as pairs // Process stereo samples as pairs
@ -244,7 +251,6 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
buffer := emptyBufs[last] buffer := emptyBufs[last]
emptyBufs = emptyBufs[:last] emptyBufs = emptyBufs[:last]
// Set buffer data with correct format
buffer.SetData(format, raw[:rawPtr], gumble.AudioSampleRate) buffer.SetData(format, raw[:rawPtr], gumble.AudioSampleRate)
source.QueueBuffer(buffer) source.QueueBuffer(buffer)

View File

@ -1,8 +1,6 @@
package main package main
import ( import (
//"math"
// "fmt"
"git.2mb.codes/~cmb/barnard/gumble/gumble" "git.2mb.codes/~cmb/barnard/gumble/gumble"
"git.2mb.codes/~cmb/barnard/uiterm" "git.2mb.codes/~cmb/barnard/uiterm"
"sort" "sort"
@ -15,6 +13,9 @@ type TreeItem struct {
func (ti TreeItem) String() string { func (ti TreeItem) String() string {
if ti.User != nil { if ti.User != nil {
if ti.User.LocallyMuted {
return "[MUTED] " + ti.User.Name
}
return ti.User.Name return ti.User.Name
} }
if ti.Channel != nil { if ti.Channel != nil {
@ -50,11 +51,7 @@ func (b *Barnard) changeVolume(users []*gumble.User, change float32) {
cv = au.GetGain() + curboost cv = au.GetGain() + curboost
ng = cv + change ng = cv + change
boost = uint16(1) boost = uint16(1)
//b.AddOutputLine(fmt.Sprintf("cv %.2f change %.2f ng %.2f",cv,change,ng))
if ng > 1.0 { if ng > 1.0 {
//1.0 will give volume of one and boost of 1
//1.1 will give volume of 1 and boost of 2
//b.AddOutputLine(fmt.Sprintf("partperc %.2f",(ng*10)))
perc := uint16((ng * 10)) - 10 perc := uint16((ng * 10)) - 10
perc += 1 perc += 1
boost = perc boost = perc
@ -63,10 +60,11 @@ func (b *Barnard) changeVolume(users []*gumble.User, change float32) {
if ng < 0 { if ng < 0 {
ng = 0.0 ng = 0.0
} }
//b.AddOutputLine(fmt.Sprintf("boost %d ng %.2f",boost,ng))
u.Boost = boost u.Boost = boost
u.Volume = ng u.Volume = ng
if !u.LocallyMuted {
au.SetGain(ng) au.SetGain(ng)
}
b.UserConfig.UpdateConfig(u) b.UserConfig.UpdateConfig(u)
} }
b.UserConfig.SaveConfig() b.UserConfig.SaveConfig()
@ -95,28 +93,58 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm
} else { } else {
b.SetSelectedUser(treeItem.User) b.SetSelectedUser(treeItem.User)
b.GotoChat() b.GotoChat()
} //select }
} //if user and not selected }
} //if enter key }
// Handle mute toggle
if treeItem.Channel != nil { if treeItem.Channel != nil {
var c = treeItem.Channel if key == *b.Hotkeys.MuteToggle {
// Toggle mute for all users in channel
users := makeUsersArray(treeItem.Channel.Users)
for _, u := range users {
b.UserConfig.ToggleMute(u)
if u.AudioSource != nil {
if u.LocallyMuted {
u.AudioSource.SetGain(0)
} else {
u.AudioSource.SetGain(u.Volume)
}
}
}
b.UiTree.Rebuild()
b.Ui.Refresh()
}
if key == *b.Hotkeys.VolumeDown { if key == *b.Hotkeys.VolumeDown {
b.changeVolume(makeUsersArray(c.Users), -0.1) b.changeVolume(makeUsersArray(treeItem.Channel.Users), -0.1)
} }
if key == *b.Hotkeys.VolumeUp { if key == *b.Hotkeys.VolumeUp {
b.changeVolume(makeUsersArray(c.Users), 0.1) b.changeVolume(makeUsersArray(treeItem.Channel.Users), 0.1)
} }
} //set volume }
if treeItem.User != nil { if treeItem.User != nil {
var u = treeItem.User if key == *b.Hotkeys.MuteToggle {
// Toggle mute for single user
b.UserConfig.ToggleMute(treeItem.User)
if treeItem.User.AudioSource != nil {
if treeItem.User.LocallyMuted {
treeItem.User.AudioSource.SetGain(0)
} else {
treeItem.User.AudioSource.SetGain(treeItem.User.Volume)
}
}
b.UiTree.Rebuild()
b.Ui.Refresh()
}
if key == *b.Hotkeys.VolumeDown { if key == *b.Hotkeys.VolumeDown {
b.changeVolume([]*gumble.User{u}, -0.1) b.changeVolume([]*gumble.User{treeItem.User}, -0.1)
} }
if key == *b.Hotkeys.VolumeUp { if key == *b.Hotkeys.VolumeUp {
b.changeVolume([]*gumble.User{u}, 0.1) b.changeVolume([]*gumble.User{treeItem.User}, 0.1)
} }
} //user highlighted }
} //func }
func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem { func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
if b.Client == nil { if b.Client == nil {