fix: add synchronization to User audio fields to prevent data races

User.AudioSource, Boost, Volume, and LocallyMuted were accessed from
both the OnAudioStream audio goroutine and the UI goroutine without
synchronization, a data race under the Go memory model.

Replace direct field access with thread-safe getter/setter methods
protected by a per-user mutex:
- SetAudioSource/GetAudioSource for the OpenAL source pointer
- SetBoost/Boost for the audio boost multiplier
- SetVolume/Volume for the volume level
- SetLocallyMuted/LocallyMuted for the local mute state

Update all call sites across config/, barnard.go, client.go,
ui_tree.go, and stream.go.
This commit is contained in:
Brandon McGinty (deepseek)
2026-08-08 20:58:53 -04:00
committed by Brandon McGinty
parent 1bdd7ac52e
commit 9dd0137975
6 changed files with 112 additions and 51 deletions
+10 -10
View File
@@ -115,17 +115,17 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm
users := makeUsersArray(treeItem.Channel.Users)
for _, u := range users {
// Explicitly set user mute state to match channel state
if channelWillBeMuted && !u.LocallyMuted {
if channelWillBeMuted && !u.LocallyMuted() {
b.UserConfig.ToggleMute(u)
} else if !channelWillBeMuted && u.LocallyMuted {
} else if !channelWillBeMuted && u.LocallyMuted() {
b.UserConfig.ToggleMute(u)
}
if u.AudioSource != nil {
if u.LocallyMuted {
u.AudioSource.SetGain(0)
if au := u.AudioSource(); au != nil {
if u.LocallyMuted() {
au.SetGain(0)
} else {
u.AudioSource.SetGain(u.Volume)
au.SetGain(u.Volume())
}
}
}
@@ -159,11 +159,11 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm
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)
if au := treeItem.User.AudioSource(); au != nil {
if treeItem.User.LocallyMuted() {
au.SetGain(0)
} else {
treeItem.User.AudioSource.SetGain(treeItem.User.Volume)
au.SetGain(treeItem.User.Volume())
}
}
b.RebuildUserChannelTreePreservingSelection()