Render file playback through the OpenAL owner

This commit is contained in:
Brandon McGinty (chatgpt)
2026-08-09 12:56:40 -04:00
committed by Brandon McGinty
parent 8c0887d562
commit db31ba33de
2 changed files with 75 additions and 62 deletions
+25 -62
View File
@@ -10,22 +10,19 @@ import (
"time"
"git.stormux.org/storm/barnard/gumble/gumble"
"git.stormux.org/storm/barnard/gumble/go-openal/openal"
)
// Player handles file playback and mixing with microphone audio
type Player struct {
client *gumble.Client
filename string
audioChan chan gumble.AudioBuffer
stopChan chan struct{}
mutex sync.Mutex
playing bool
errorFunc func(error)
client *gumble.Client
filename string
audioChan chan gumble.AudioBuffer
stopChan chan struct{}
mutex sync.Mutex
playing bool
errorFunc func(error)
// Local playback
localSource *openal.Source
localBuffers openal.Buffers
localPlayback func([]byte)
}
// New creates a new file player
@@ -44,6 +41,14 @@ func (p *Player) SetErrorFunc(f func(error)) {
p.errorFunc = f
}
// SetLocalPlayback sets the callback that plays file audio locally. The
// callback is called with nil when playback stops and should release resources.
func (p *Player) SetLocalPlayback(f func([]byte)) {
p.mutex.Lock()
defer p.mutex.Unlock()
p.localPlayback = f
}
func (p *Player) reportError(err error) {
p.mutex.Lock()
errorFunc := p.errorFunc
@@ -65,14 +70,6 @@ func (p *Player) PlayFile(filename string) error {
p.filename = filename
// Initialize local playback
source := openal.NewSource()
p.localSource = &source
p.localSource.SetGain(1.0)
// Create buffers for local playback
p.localBuffers = openal.NewBuffers(64)
// Start the file reading goroutine
p.playing = true
p.stopChan = make(chan struct{})
@@ -93,15 +90,8 @@ func (p *Player) Stop() error {
close(p.stopChan)
p.playing = false
// Clean up local playback
if p.localSource != nil {
p.localSource.Stop()
p.localSource.Delete()
p.localSource = nil
}
if p.localBuffers != nil {
p.localBuffers.Delete()
p.localBuffers = nil
if p.localPlayback != nil {
p.localPlayback(nil)
}
// Drain the audio channel
@@ -129,32 +119,12 @@ func (p *Player) GetAudioFrame() []int16 {
}
}
// playLocalAudio plays audio through the local OpenAL source
func (p *Player) playLocalAudio(data []byte) {
if p.localSource == nil {
return
}
// Reclaim processed buffers
if n := p.localSource.BuffersProcessed(); n > 0 {
reclaimedBufs := make(openal.Buffers, n)
p.localSource.UnqueueBuffers(reclaimedBufs)
p.localBuffers = append(p.localBuffers, reclaimedBufs...)
}
// If we have available buffers, queue more audio
if len(p.localBuffers) > 0 {
buffer := p.localBuffers[len(p.localBuffers)-1]
p.localBuffers = p.localBuffers[:len(p.localBuffers)-1]
// Set buffer data as stereo
buffer.SetData(openal.FormatStereo16, data, gumble.AudioSampleRate)
p.localSource.QueueBuffer(buffer)
// Start playing if not already
if p.localSource.State() != openal.Playing {
p.localSource.Play()
}
p.mutex.Lock()
localPlayback := p.localPlayback
p.mutex.Unlock()
if localPlayback != nil {
localPlayback(data)
}
}
@@ -204,15 +174,8 @@ func (p *Player) readFileAudio() {
// File finished playing
p.mutex.Lock()
p.playing = false
// Clean up local playback
if p.localSource != nil {
p.localSource.Stop()
p.localSource.Delete()
p.localSource = nil
}
if p.localBuffers != nil {
p.localBuffers.Delete()
p.localBuffers = nil
if p.localPlayback != nil {
p.localPlayback(nil)
}
p.mutex.Unlock()
cmd.Wait()
+50
View File
@@ -82,6 +82,8 @@ type Stream struct {
micAGC *audio.AGC
micAGCRight *audio.AGC
filePlayer FilePlayer
localSource *openal.Source
localBuffers openal.Buffers
recorderMu sync.RWMutex
errorFunc func(error) // called on capture errors
recorder Recorder
@@ -200,6 +202,54 @@ func (s *Stream) SetNoiseProcessor(np NoiseProcessor) {
func (s *Stream) SetFilePlayer(fp FilePlayer) {
s.filePlayer = fp
if player, ok := fp.(interface{ SetLocalPlayback(func([]byte)) }); ok {
player.SetLocalPlayback(s.playLocalAudio)
}
}
func (s *Stream) playLocalAudio(data []byte) {
s.render(func() {
if data == nil {
if s.localSource != nil {
s.localSource.Stop()
queued := s.localSource.BuffersQueued()
if queued > 0 {
buffers := make(openal.Buffers, queued)
s.localSource.UnqueueBuffers(buffers)
s.localBuffers = append(s.localBuffers, buffers...)
}
s.localSource.Delete()
s.localSource = nil
}
if len(s.localBuffers) > 0 {
s.localBuffers.Delete()
s.localBuffers = nil
}
return
}
if s.localSource == nil {
source := openal.NewSource()
source.SetGain(1)
s.localSource = &source
s.localBuffers = openal.NewBuffers(64)
}
if n := s.localSource.BuffersProcessed(); n > 0 {
buffers := make(openal.Buffers, n)
s.localSource.UnqueueBuffers(buffers)
s.localBuffers = append(s.localBuffers, buffers...)
}
if len(s.localBuffers) == 0 {
return
}
last := len(s.localBuffers) - 1
buffer := s.localBuffers[last]
s.localBuffers = s.localBuffers[:last]
buffer.SetData(openal.FormatStereo16, data, gumble.AudioSampleRate)
s.localSource.QueueBuffer(buffer)
if s.localSource.State() != openal.Playing {
s.localSource.Play()
}
})
}
func (s *Stream) GetFilePlayer() FilePlayer {