Render file playback through the OpenAL owner
This commit is contained in:
committed by
Brandon McGinty
parent
8c0887d562
commit
db31ba33de
+18
-55
@@ -10,7 +10,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.stormux.org/storm/barnard/gumble/gumble"
|
"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
|
// Player handles file playback and mixing with microphone audio
|
||||||
@@ -23,9 +22,7 @@ type Player struct {
|
|||||||
playing bool
|
playing bool
|
||||||
errorFunc func(error)
|
errorFunc func(error)
|
||||||
|
|
||||||
// Local playback
|
localPlayback func([]byte)
|
||||||
localSource *openal.Source
|
|
||||||
localBuffers openal.Buffers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new file player
|
// New creates a new file player
|
||||||
@@ -44,6 +41,14 @@ func (p *Player) SetErrorFunc(f func(error)) {
|
|||||||
p.errorFunc = f
|
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) {
|
func (p *Player) reportError(err error) {
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
errorFunc := p.errorFunc
|
errorFunc := p.errorFunc
|
||||||
@@ -65,14 +70,6 @@ func (p *Player) PlayFile(filename string) error {
|
|||||||
|
|
||||||
p.filename = filename
|
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
|
// Start the file reading goroutine
|
||||||
p.playing = true
|
p.playing = true
|
||||||
p.stopChan = make(chan struct{})
|
p.stopChan = make(chan struct{})
|
||||||
@@ -93,15 +90,8 @@ func (p *Player) Stop() error {
|
|||||||
close(p.stopChan)
|
close(p.stopChan)
|
||||||
p.playing = false
|
p.playing = false
|
||||||
|
|
||||||
// Clean up local playback
|
if p.localPlayback != nil {
|
||||||
if p.localSource != nil {
|
p.localPlayback(nil)
|
||||||
p.localSource.Stop()
|
|
||||||
p.localSource.Delete()
|
|
||||||
p.localSource = nil
|
|
||||||
}
|
|
||||||
if p.localBuffers != nil {
|
|
||||||
p.localBuffers.Delete()
|
|
||||||
p.localBuffers = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain the audio channel
|
// 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) {
|
func (p *Player) playLocalAudio(data []byte) {
|
||||||
if p.localSource == nil {
|
p.mutex.Lock()
|
||||||
return
|
localPlayback := p.localPlayback
|
||||||
}
|
p.mutex.Unlock()
|
||||||
|
if localPlayback != nil {
|
||||||
// Reclaim processed buffers
|
localPlayback(data)
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,15 +174,8 @@ func (p *Player) readFileAudio() {
|
|||||||
// File finished playing
|
// File finished playing
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
p.playing = false
|
p.playing = false
|
||||||
// Clean up local playback
|
if p.localPlayback != nil {
|
||||||
if p.localSource != nil {
|
p.localPlayback(nil)
|
||||||
p.localSource.Stop()
|
|
||||||
p.localSource.Delete()
|
|
||||||
p.localSource = nil
|
|
||||||
}
|
|
||||||
if p.localBuffers != nil {
|
|
||||||
p.localBuffers.Delete()
|
|
||||||
p.localBuffers = nil
|
|
||||||
}
|
}
|
||||||
p.mutex.Unlock()
|
p.mutex.Unlock()
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ type Stream struct {
|
|||||||
micAGC *audio.AGC
|
micAGC *audio.AGC
|
||||||
micAGCRight *audio.AGC
|
micAGCRight *audio.AGC
|
||||||
filePlayer FilePlayer
|
filePlayer FilePlayer
|
||||||
|
localSource *openal.Source
|
||||||
|
localBuffers openal.Buffers
|
||||||
recorderMu sync.RWMutex
|
recorderMu sync.RWMutex
|
||||||
errorFunc func(error) // called on capture errors
|
errorFunc func(error) // called on capture errors
|
||||||
recorder Recorder
|
recorder Recorder
|
||||||
@@ -200,6 +202,54 @@ func (s *Stream) SetNoiseProcessor(np NoiseProcessor) {
|
|||||||
|
|
||||||
func (s *Stream) SetFilePlayer(fp FilePlayer) {
|
func (s *Stream) SetFilePlayer(fp FilePlayer) {
|
||||||
s.filePlayer = fp
|
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 {
|
func (s *Stream) GetFilePlayer() FilePlayer {
|
||||||
|
|||||||
Reference in New Issue
Block a user