From 157358eb4dd2e0078a8882c4fdb7ec5944cb21ee Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 21 Aug 2026 16:02:03 -0700 Subject: [PATCH 1/2] impl --- buffers.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/buffers.go b/buffers.go index b946072..19495af 100644 --- a/buffers.go +++ b/buffers.go @@ -11,19 +11,32 @@ type sample interface { byte | int8 | int16 | int32 | int64 | float32 | float64 } +type FullFramesOption[T ~[]S, S sample] func(*fullFrameBuffer[T, S]) + +func DropTailOnClose[T ~[]S, S sample]() FullFramesOption[T, S] { + return func(b *fullFrameBuffer[T, S]) { + b.dropTail = true + } +} + // FullFrames creates a writer that only writes full frames of a given size to the underlying writer (except the last one). -func FullFrames[T ~[]S, S sample](w WriteCloser[T], frameSize int) WriteCloser[T] { +func FullFrames[T ~[]S, S sample](w WriteCloser[T], frameSize int, opts ...FullFramesOption[T, S]) WriteCloser[T] { if frameSize <= 0 { panic("invalid frame size") } - return &fullFrameBuffer[T, S]{ + b := &fullFrameBuffer[T, S]{ w: w, frameSize: frameSize, buf: make([]S, 0, frameSize), } + for _, opt := range opts { + opt(b) + } + return b } type fullFrameBuffer[T ~[]S, S sample] struct { + dropTail bool // Avoid flushing partial frames on Close() frameSize int mu sync.Mutex w WriteCloser[T] @@ -72,7 +85,7 @@ func (b *fullFrameBuffer[T, S]) flush(force bool) error { func (b *fullFrameBuffer[T, S]) Close() error { b.mu.Lock() defer b.mu.Unlock() - err := b.flush(true) + err := b.flush(!b.dropTail) err2 := b.w.Close() return errors.Join(err, err2) } From b703e3d84e56ce3f973e3bd4a8a4a2941b677076 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 21 Aug 2026 16:06:08 -0700 Subject: [PATCH 2/2] test --- buffers_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/buffers_test.go b/buffers_test.go index a41b27c..ec9f2c3 100644 --- a/buffers_test.go +++ b/buffers_test.go @@ -46,3 +46,30 @@ func TestFullFrames(t *testing.T) { {7}, }, got) } + +func TestFullFramesDropTailOnClose(t *testing.T) { + var got []PCM16Sample + w := FullFrames(NewPCM16FrameWriter(&got, 8000), 2, DropTailOnClose[PCM16Sample]()) + for _, f := range []PCM16Sample{ + {}, + {1}, + {2, 3}, + {4, 5, 6}, + {7}, + } { + err := w.WriteSample(f) + require.NoError(t, err) + } + require.Equal(t, []PCM16Sample{ + {1, 2}, + {3, 4}, + {5, 6}, + }, got) + err := w.Close() + require.NoError(t, err) + require.Equal(t, []PCM16Sample{ + {1, 2}, + {3, 4}, + {5, 6}, + }, got) +}