nativeaudio

audio playback for Go
Log | Files | Refs | README | LICENSE

commit 87ea90df507740bf93d4cf2840953b0b38977098
parent 9ffd7724e3c2f8bec605d5b958910a57f6bb930d
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Thu, 17 Sep 2026 11:58:19 -0400

test: play a silent file twice and check each call runs full length

Play was untested, so neither a second call failing on the process-wide
audio context nor the tail being cut off when the source hit EOF could
be caught. A generated second of silence keeps the test quiet; timing
bounds catch an early return, and the second iteration catches a context
that cannot be reused. Skips when no audio output is available.

Diffstat:
Ainternal/test/play_test.go | 48++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+), 0 deletions(-)

diff --git a/internal/test/play_test.go b/internal/test/play_test.go @@ -0,0 +1,48 @@ +package test + +import ( + "os/exec" + "runtime" + "strings" + "testing" + "time" + + "git.sr.ht/~jackmordaunt/nativeaudio" +) + +// TestPlayTwice plays one second of silence twice in the same process. +// +// Each call must take at least the file's duration: returning early means +// the tail of the audio was cut off. The second call must succeed at all: +// the playback context is process-wide and used to be re-created per call, +// which the audio backend refuses. +// +// The test skips when no audio output is available. +func TestPlayTwice(t *testing.T) { + if runtime.GOOS != "windows" && runtime.GOOS != "darwin" { + // Other platforms play through ffplay; that path has its own test. + if _, err := exec.LookPath("ffplay"); err != nil { + t.Skip("ffplay not installed") + } + } + const seconds = 1 + path := writeTemp(t, "silence.wav", silentWAV(44100, 2, seconds)) + for i := 1; i <= 2; i++ { + start := time.Now() + err := nativeaudio.Play(path) + elapsed := time.Since(start) + if err != nil { + if i == 1 && strings.Contains(err.Error(), "starting playback context") { + t.Skipf("no audio output available: %v", err) + } + t.Fatalf("play %d: %v", i, err) + } + t.Logf("play %d took %v", i, elapsed.Round(time.Millisecond)) + if min := time.Duration(seconds) * time.Second * 9 / 10; elapsed < min { + t.Errorf("play %d returned after %v, want at least %v: audio tail was cut off", i, elapsed, min) + } + if max := 10 * time.Second; elapsed > max { + t.Errorf("play %d took %v, want under %v", i, elapsed, max) + } + } +}