From d07d7342daa1add4099345ecaf9bac091215bb00 Mon Sep 17 00:00:00 2001 From: "Brandon McGinty (chatgpt)" Date: Sun, 9 Aug 2026 14:50:01 -0400 Subject: [PATCH] Release audio resources before reconnecting --- barnard.go | 17 +++++++++++++++++ client.go | 1 + client_notification_test.go | 8 ++++++++ fix.txt | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/barnard.go b/barnard.go index 8f8f802..d2df2f8 100644 --- a/barnard.go +++ b/barnard.go @@ -81,6 +81,23 @@ type Barnard struct { adminACL *gumble.ACL } +// cleanupConnectionAudio releases connection-owned audio resources before a +// reconnect replaces them. It is intentionally idempotent for repeated +// disconnect notifications. +func (b *Barnard) cleanupConnectionAudio() { + if b.Stream != nil { + stream := b.Stream + b.Stream = nil + stream.Destroy() + } + b.FileStreamMutex.Lock() + if b.FileStream != nil { + _ = b.FileStream.Stop() + b.FileStream = nil + } + b.FileStreamMutex.Unlock() +} + func (b *Barnard) StopTransmission() { if b.Tx { b.Notify("micdown", "me", "") diff --git a/client.go b/client.go index cc8078f..fcba652 100644 --- a/client.go +++ b/client.go @@ -168,6 +168,7 @@ func (b *Barnard) OnDisconnect(e *gumble.DisconnectEvent) { reason = e.String } b.stopRecordingForDisconnect() + b.cleanupConnectionAudio() // Tone test cleanup if b.ToneTest { diff --git a/client_notification_test.go b/client_notification_test.go index 133642e..0d33cba 100644 --- a/client_notification_test.go +++ b/client_notification_test.go @@ -53,6 +53,14 @@ func TestNotificationExpansionIsSinglePassAndNotifyDoesNotBlock(t *testing.T) { } } +// Regression: reconnect replaced Stream without destroying the old capture +// and renderer resources. Cleanup must be safe for repeated disconnects. +func TestCleanupConnectionAudioIsIdempotent(t *testing.T) { + b := &Barnard{} + b.cleanupConnectionAudio() + b.cleanupConnectionAudio() +} + func TestUserChangeNotification(t *testing.T) { current := &gumble.Channel{ID: 1, Name: "Current"} other := &gumble.Channel{ID: 2, Name: "Other"} diff --git a/fix.txt b/fix.txt index 501511a..61f36c1 100644 --- a/fix.txt +++ b/fix.txt @@ -92,7 +92,7 @@ Priority 1: transport, lifecycle, and correctness Stop and join all audio stream goroutines before renderer shutdown; make render reject work after shutdown without panicking. -11. Reconnect leaks the old audio stream +[x] 11. Reconnect leaks the old audio stream File: client.go OnDisconnect starts reconnecting but never destroys the existing Stream or stops its file player/capture routine. connect creates a new Stream and