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
|
||||
|
||||
// Added for tone test mode (bypasses all soundcard/OpenAL)
|
||||
ToneTest bool
|
||||
ToneTestOutput string
|
||||
toneTestStop chan struct{}
|
||||
toneTestSaver *AudioFileSaver
|
||||
ToneTest bool
|
||||
ToneTestOutput string
|
||||
toneTestStop chan struct{}
|
||||
toneTestSaver *AudioFileSaver
|
||||
toneTestSaverDetach gumble.Detacher
|
||||
|
||||
// Added for recording
|
||||
RecordingMutex sync.Mutex
|
||||
@@ -98,6 +99,17 @@ func (b *Barnard) cleanupConnectionAudio() {
|
||||
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() {
|
||||
if b.Tx {
|
||||
b.Notify("micdown", "me", "")
|
||||
|
||||
@@ -68,7 +68,7 @@ func (b *Barnard) connect(reconnect bool) bool {
|
||||
return false
|
||||
}
|
||||
b.toneTestSaver = saver
|
||||
b.Client.Config.AttachAudio(saver)
|
||||
b.toneTestSaverDetach = b.Client.Config.AttachAudio(saver)
|
||||
|
||||
b.Connected = true
|
||||
if b.toneTestAutoTransmit() {
|
||||
@@ -191,10 +191,7 @@ func (b *Barnard) OnDisconnect(e *gumble.DisconnectEvent) {
|
||||
close(b.toneTestStop)
|
||||
b.toneTestStop = nil
|
||||
}
|
||||
if b.toneTestSaver != nil {
|
||||
b.toneTestSaver.Stop()
|
||||
b.toneTestSaver = nil
|
||||
}
|
||||
b.cleanupToneTestAudio()
|
||||
}
|
||||
|
||||
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
|
||||
// audio to a single raw 16-bit little-endian stereo 48kHz file.
|
||||
type AudioFileSaver struct {
|
||||
file *os.File
|
||||
stop chan struct{}
|
||||
mu sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
file *os.File
|
||||
stop chan struct{}
|
||||
mu sync.Mutex
|
||||
stopped bool
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// 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,
|
||||
// and closes the output file.
|
||||
func (s *AudioFileSaver) Stop() {
|
||||
s.mu.Lock()
|
||||
if s.stopped {
|
||||
s.mu.Unlock()
|
||||
return
|
||||
}
|
||||
s.stopped = true
|
||||
close(s.stop)
|
||||
s.mu.Unlock()
|
||||
|
||||
s.wg.Wait()
|
||||
s.file.Close()
|
||||
s.mu.Lock()
|
||||
_ = s.file.Close()
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// OnAudioStream implements gumble.AudioListener.
|
||||
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.mu.Unlock()
|
||||
|
||||
fmt.Fprintf(os.Stderr, "tonetest: incoming audio stream from %s\n", e.User.Name)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
|
||||
|
||||
@@ -24,3 +24,27 @@ func TestNewAudioFileSaverReportsUnavailableOutputPath(t *testing.T) {
|
||||
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