fix: fix data race on micVolume field
micVolume was accessed from both the UI goroutine (SetMicVolume, GetMicVolume) and the audio source goroutine (sourceRoutine) without synchronization, a data race under the Go memory model. Switch to atomic.Uint32 storing float32 bits to make reads and writes safe across goroutines.
This commit is contained in:
committed by
Brandon McGinty
parent
676c27fe30
commit
1bdd7ac52e
@@ -3,8 +3,10 @@ package gumbleopenal
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.stormux.org/storm/barnard/audio"
|
"git.stormux.org/storm/barnard/audio"
|
||||||
@@ -60,7 +62,7 @@ type Stream struct {
|
|||||||
sourceFormat openal.Format
|
sourceFormat openal.Format
|
||||||
sourceChannels int
|
sourceChannels int
|
||||||
sourceFrameSize int
|
sourceFrameSize int
|
||||||
micVolume float32
|
micVolume atomic.Uint32 // float32 stored as bits
|
||||||
sourceStop chan bool
|
sourceStop chan bool
|
||||||
|
|
||||||
deviceSink *openal.Device
|
deviceSink *openal.Device
|
||||||
@@ -110,7 +112,6 @@ func New(client *gumble.Client, inputDevice *string, outputDevice *string, test
|
|||||||
sourceFormat: inputFormat,
|
sourceFormat: inputFormat,
|
||||||
sourceChannels: sourceChannels,
|
sourceChannels: sourceChannels,
|
||||||
sourceFrameSize: frmsz,
|
sourceFrameSize: frmsz,
|
||||||
micVolume: 1.0,
|
|
||||||
micAGC: audio.NewAGC(), // Always enable AGC for outgoing mic
|
micAGC: audio.NewAGC(), // Always enable AGC for outgoing mic
|
||||||
}
|
}
|
||||||
if sourceChannels == 2 {
|
if sourceChannels == 2 {
|
||||||
@@ -209,7 +210,11 @@ func (s *Stream) StopSource() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stream) GetMicVolume() float32 {
|
func (s *Stream) GetMicVolume() float32 {
|
||||||
return s.micVolume
|
bits := s.micVolume.Load()
|
||||||
|
if bits == 0 {
|
||||||
|
return 1.0 // default on first access
|
||||||
|
}
|
||||||
|
return math.Float32frombits(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stream) SetMicVolume(change float32, relative bool) {
|
func (s *Stream) SetMicVolume(change float32, relative bool) {
|
||||||
@@ -225,7 +230,7 @@ func (s *Stream) SetMicVolume(change float32, relative bool) {
|
|||||||
if val <= 0 {
|
if val <= 0 {
|
||||||
val = 0
|
val = 0
|
||||||
}
|
}
|
||||||
s.micVolume = val
|
s.micVolume.Store(math.Float32bits(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
||||||
@@ -417,8 +422,9 @@ func (s *Stream) sourceRoutine(inputDevice *string) {
|
|||||||
hasMicInput = true
|
hasMicInput = true
|
||||||
for i := 0; i < sampleCount; i++ {
|
for i := 0; i < sampleCount; i++ {
|
||||||
sample := int16(binary.LittleEndian.Uint16(buff[i*2:]))
|
sample := int16(binary.LittleEndian.Uint16(buff[i*2:]))
|
||||||
if s.micVolume != 1.0 {
|
vol := s.GetMicVolume()
|
||||||
sample = int16(float32(sample) * s.micVolume)
|
if vol != 1.0 {
|
||||||
|
sample = int16(float32(sample) * vol)
|
||||||
}
|
}
|
||||||
int16Buffer[i] = sample
|
int16Buffer[i] = sample
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user