fix: prevent Play() deadlock when device is not open
Play() held mu then called SwitchDevice() which also tried to acquire mu, causing a deadlock. Replace with direct call to openDeviceLocked() which does not lock. Add regression test that verifies Play() returns an error (not deadlock) when called on an uninitialized mixer.
This commit is contained in:
@@ -2,8 +2,45 @@ package mixer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"rhemawavetech.com/rhemawave/internal/db"
|
||||
)
|
||||
|
||||
// TestPlayDoesNotDeadlockWhenUninitialized verifies that Play() returns an error
|
||||
// (not a deadlock) when the mixer has not been initialized.
|
||||
// The old code would deadlock because Play() held mu then called SwitchDevice()
|
||||
// which also tried to acquire mu.
|
||||
func TestPlayDoesNotDeadlockWhenUninitialized(t *testing.T) {
|
||||
// Ensure mixer is in uninitialized state
|
||||
mu.Lock()
|
||||
wasInited := inited
|
||||
inited = false
|
||||
deviceOpen = false
|
||||
mu.Unlock()
|
||||
|
||||
defer func() {
|
||||
mu.Lock()
|
||||
inited = wasInited
|
||||
mu.Unlock()
|
||||
}()
|
||||
|
||||
cfg := &db.AppConfig{AudioEnabled: true}
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- Play("nonexistent.wav", false, cfg)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-done:
|
||||
if err == nil {
|
||||
t.Fatal("Play() returned nil error on uninitialized mixer, want error")
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("Play() deadlocked on uninitialized mixer (did not return within 5s)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSinkLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user