Detach tone-test savers on reconnect
This commit is contained in:
committed by
Brandon McGinty
parent
b23afebdb3
commit
bad4e8172a
+16
-4
@@ -64,10 +64,11 @@ type Barnard struct {
|
|||||||
FileStreamMutex sync.Mutex
|
FileStreamMutex sync.Mutex
|
||||||
|
|
||||||
// Added for tone test mode (bypasses all soundcard/OpenAL)
|
// Added for tone test mode (bypasses all soundcard/OpenAL)
|
||||||
ToneTest bool
|
ToneTest bool
|
||||||
ToneTestOutput string
|
ToneTestOutput string
|
||||||
toneTestStop chan struct{}
|
toneTestStop chan struct{}
|
||||||
toneTestSaver *AudioFileSaver
|
toneTestSaver *AudioFileSaver
|
||||||
|
toneTestSaverDetach gumble.Detacher
|
||||||
|
|
||||||
// Added for recording
|
// Added for recording
|
||||||
RecordingMutex sync.Mutex
|
RecordingMutex sync.Mutex
|
||||||
@@ -98,6 +99,17 @@ func (b *Barnard) cleanupConnectionAudio() {
|
|||||||
b.FileStreamMutex.Unlock()
|
b.FileStreamMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Barnard) cleanupToneTestAudio() {
|
||||||
|
if b.toneTestSaverDetach != nil {
|
||||||
|
b.toneTestSaverDetach.Detach()
|
||||||
|
b.toneTestSaverDetach = nil
|
||||||
|
}
|
||||||
|
if b.toneTestSaver != nil {
|
||||||
|
b.toneTestSaver.Stop()
|
||||||
|
b.toneTestSaver = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Barnard) StopTransmission() {
|
func (b *Barnard) StopTransmission() {
|
||||||
if b.Tx {
|
if b.Tx {
|
||||||
b.Notify("micdown", "me", "")
|
b.Notify("micdown", "me", "")
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ func (b *Barnard) connect(reconnect bool) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
b.toneTestSaver = saver
|
b.toneTestSaver = saver
|
||||||
b.Client.Config.AttachAudio(saver)
|
b.toneTestSaverDetach = b.Client.Config.AttachAudio(saver)
|
||||||
|
|
||||||
b.Connected = true
|
b.Connected = true
|
||||||
if b.toneTestAutoTransmit() {
|
if b.toneTestAutoTransmit() {
|
||||||
@@ -191,10 +191,7 @@ func (b *Barnard) OnDisconnect(e *gumble.DisconnectEvent) {
|
|||||||
close(b.toneTestStop)
|
close(b.toneTestStop)
|
||||||
b.toneTestStop = nil
|
b.toneTestStop = nil
|
||||||
}
|
}
|
||||||
if b.toneTestSaver != nil {
|
b.cleanupToneTestAudio()
|
||||||
b.toneTestSaver.Stop()
|
|
||||||
b.toneTestSaver = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Notify("disconnect", "me", reason)
|
b.Notify("disconnect", "me", reason)
|
||||||
|
|||||||
+24
-6
@@ -65,10 +65,11 @@ func StartToneGenerator(client *gumble.Client, stop <-chan struct{}) {
|
|||||||
// AudioFileSaver implements gumble.AudioListener and writes all incoming PCM
|
// AudioFileSaver implements gumble.AudioListener and writes all incoming PCM
|
||||||
// audio to a single raw 16-bit little-endian stereo 48kHz file.
|
// audio to a single raw 16-bit little-endian stereo 48kHz file.
|
||||||
type AudioFileSaver struct {
|
type AudioFileSaver struct {
|
||||||
file *os.File
|
file *os.File
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
wg sync.WaitGroup
|
stopped bool
|
||||||
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAudioFileSaver creates the output file and returns a configured saver.
|
// NewAudioFileSaver creates the output file and returns a configured saver.
|
||||||
@@ -95,15 +96,32 @@ func NewAudioFileSaver(path string) (*AudioFileSaver, error) {
|
|||||||
// Stop closes the stop channel, waits for all stream goroutines to finish,
|
// Stop closes the stop channel, waits for all stream goroutines to finish,
|
||||||
// and closes the output file.
|
// and closes the output file.
|
||||||
func (s *AudioFileSaver) Stop() {
|
func (s *AudioFileSaver) Stop() {
|
||||||
|
s.mu.Lock()
|
||||||
|
if s.stopped {
|
||||||
|
s.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.stopped = true
|
||||||
close(s.stop)
|
close(s.stop)
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
s.file.Close()
|
s.mu.Lock()
|
||||||
|
_ = s.file.Close()
|
||||||
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnAudioStream implements gumble.AudioListener.
|
// OnAudioStream implements gumble.AudioListener.
|
||||||
func (s *AudioFileSaver) OnAudioStream(e *gumble.AudioStreamEvent) {
|
func (s *AudioFileSaver) OnAudioStream(e *gumble.AudioStreamEvent) {
|
||||||
fmt.Fprintf(os.Stderr, "tonetest: incoming audio stream from %s\n", e.User.Name)
|
s.mu.Lock()
|
||||||
|
if s.stopped {
|
||||||
|
s.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "tonetest: incoming audio stream from %s\n", e.User.Name)
|
||||||
go func() {
|
go func() {
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
|
|
||||||
|
|||||||
@@ -24,3 +24,27 @@ func TestNewAudioFileSaverReportsUnavailableOutputPath(t *testing.T) {
|
|||||||
t.Fatalf("got saver=%v err=%v", saver, err)
|
t.Fatalf("got saver=%v err=%v", saver, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testDetacher struct{ detached bool }
|
||||||
|
|
||||||
|
func (d *testDetacher) Detach() { d.detached = true }
|
||||||
|
|
||||||
|
// Regression: reconnecting tone-test mode kept prior savers attached to the
|
||||||
|
// shared audio listener list, causing callbacks to write to closed files.
|
||||||
|
func TestCleanupToneTestAudioDetachesSaver(t *testing.T) {
|
||||||
|
saver, err := NewAudioFileSaver(filepath.Join(t.TempDir(), "tone.pcm"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
detacher := &testDetacher{}
|
||||||
|
b := &Barnard{toneTestSaver: saver, toneTestSaverDetach: detacher}
|
||||||
|
|
||||||
|
b.cleanupToneTestAudio()
|
||||||
|
if !detacher.detached {
|
||||||
|
t.Fatal("tone saver listener was not detached")
|
||||||
|
}
|
||||||
|
if b.toneTestSaver != nil || b.toneTestSaverDetach != nil {
|
||||||
|
t.Fatal("tone saver cleanup retained connection state")
|
||||||
|
}
|
||||||
|
b.cleanupToneTestAudio()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user