Start work on improving recordings.
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user