Start work on improving recordings.

This commit is contained in:
Storm Dragon
2026-05-23 23:33:30 -04:00
parent 08b484f106
commit 3e06de7501
8 changed files with 662 additions and 105 deletions
+109 -3
View File
@@ -103,7 +103,7 @@ func TestCleanupOldRecordings(t *testing.T) {
}
}
func TestMixFrameClipsAndSumsSources(t *testing.T) {
func TestMixFrameAppliesHeadroomForMultipleSources(t *testing.T) {
a := make(chan []byte, 1)
b := make(chan []byte, 1)
a <- pcmFrame(20000)
@@ -116,12 +116,79 @@ func TestMixFrameClipsAndSumsSources(t *testing.T) {
for i := 0; i < len(out); i += 2 {
got := int16(binary.LittleEndian.Uint16(out[i:]))
if got != 32767 {
t.Fatalf("sample %d = %d, expected clipped 32767", i/2, got)
if got != 28071 {
t.Fatalf("sample %d = %d, expected headroom-adjusted 28071", i/2, got)
}
}
}
func TestMixFrameLimiterPreservesNormalSpeechLevel(t *testing.T) {
a := make(chan []byte, 1)
a <- pcmFrame(12000)
out := mixFrame([]chan []byte{a})
for i := 0; i < len(out); i += 2 {
got := int16(binary.LittleEndian.Uint16(out[i:]))
if got != 12000 {
t.Fatalf("sample %d = %d, expected unchanged 12000", i/2, got)
}
}
}
func TestMixFrameHandlesQuietAndLoudSources(t *testing.T) {
a := make(chan []byte, 1)
b := make(chan []byte, 1)
a <- pcmFrame(1000)
b <- pcmFrame(20000)
out := mixFrame([]chan []byte{a, b})
for i := 0; i < len(out); i += 2 {
got := int16(binary.LittleEndian.Uint16(out[i:]))
if got != 14849 {
t.Fatalf("sample %d = %d, expected mixed quiet/loud sample 14849", i/2, got)
}
}
}
func TestMixFrameLimiterBoundsOverloadedSamples(t *testing.T) {
a := make(chan []byte, 1)
b := make(chan []byte, 1)
a <- pcmFrame(32000)
b <- pcmFrame(32000)
out := mixFrame([]chan []byte{a, b})
for i := 0; i < len(out); i += 2 {
got := int16(binary.LittleEndian.Uint16(out[i:]))
if got <= 0 || got > 32767 {
t.Fatalf("sample %d = %d, expected bounded positive sample", i/2, got)
}
if got >= 32767 {
t.Fatalf("sample %d = %d, expected limiter below hard clip", i/2, got)
}
}
}
func TestMixFrameConsumesOldestQueuedFrame(t *testing.T) {
source := make(chan []byte, 2)
source <- pcmFrame(1000)
source <- pcmFrame(2000)
out := mixFrame([]chan []byte{source})
if len(out) != bytesPerFrame {
t.Fatalf("mixed frame has length %d, expected %d", len(out), bytesPerFrame)
}
for i := 0; i < len(out); i += 2 {
got := int16(binary.LittleEndian.Uint16(out[i:]))
if got != 1000 {
t.Fatalf("sample %d = %d, expected oldest queued sample 1000", i/2, got)
}
}
if queued := len(source); queued != 1 {
t.Fatalf("queued frames after mix = %d, expected 1", queued)
}
}
func TestMixFrameReturnsNilForSilence(t *testing.T) {
if out := mixFrame(nil); out != nil {
t.Fatalf("expected nil silent frame, got %d bytes", len(out))
@@ -162,6 +229,45 @@ func TestRecorderCreatesPlayableOgg(t *testing.T) {
}
}
func TestSyntheticRecordingCreatesPlayableOgg(t *testing.T) {
if _, err := exec.LookPath("ffmpeg"); err != nil {
t.Skip("ffmpeg not installed")
}
if _, err := exec.LookPath("ffprobe"); err != nil {
t.Skip("ffprobe not installed")
}
result, err := RunSyntheticRecording(t.TempDir(), 3, 100*time.Millisecond)
if err != nil {
t.Fatal(err)
}
if result.Metrics.DecoderStarts != 3 {
t.Fatalf("decoder starts = %d, expected 3", result.Metrics.DecoderStarts)
}
if result.Metrics.DecoderStops != 3 {
t.Fatalf("decoder stops = %d, expected 3", result.Metrics.DecoderStops)
}
if result.Metrics.DroppedMixedFrames != 0 {
t.Fatalf("dropped mixed frames = %d, expected 0", result.Metrics.DroppedMixedFrames)
}
cmd := exec.Command(
"ffprobe",
"-v", "error",
"-select_streams", "a:0",
"-show_entries", "stream=codec_name",
"-of", "default=noprint_wrappers=1:nokey=1",
result.Path,
)
out, err := cmd.Output()
if err != nil {
t.Fatal(err)
}
if strings.TrimSpace(string(out)) != "opus" {
t.Fatalf("expected opus stream, got %q", strings.TrimSpace(string(out)))
}
}
func pcmFrame(sample int16) []byte {
out := make([]byte, bytesPerFrame)
for i := 0; i < len(out); i += 2 {