202 lines
4.2 KiB
Go
202 lines
4.2 KiB
Go
// ABOUTME: Unit tests for PCM encoder
|
|
// ABOUTME: Tests 16-bit and 24-bit PCM encoding
|
|
package encode
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
"github.com/Sendspin/sendspin-go/pkg/audio"
|
|
)
|
|
|
|
func TestNewPCM(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
format audio.Format
|
|
wantErr bool
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "valid 16-bit PCM",
|
|
format: audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 16,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "valid 24-bit PCM",
|
|
format: audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 24,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "invalid codec",
|
|
format: audio.Format{
|
|
Codec: "opus",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 16,
|
|
},
|
|
wantErr: true,
|
|
errContains: "invalid codec",
|
|
},
|
|
{
|
|
name: "unsupported bit depth",
|
|
format: audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 32,
|
|
},
|
|
wantErr: true,
|
|
errContains: "unsupported bit depth",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
encoder, err := NewPCM(tt.format)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("NewPCM() expected error, got nil")
|
|
} else if tt.errContains != "" && !contains(err.Error(), tt.errContains) {
|
|
t.Errorf("NewPCM() error = %v, want error containing %v", err, tt.errContains)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("NewPCM() unexpected error = %v", err)
|
|
}
|
|
if encoder == nil {
|
|
t.Errorf("NewPCM() returned nil encoder")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPCMEncoder_Encode16Bit(t *testing.T) {
|
|
format := audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 16,
|
|
}
|
|
|
|
encoder, err := NewPCM(format)
|
|
if err != nil {
|
|
t.Fatalf("NewPCM() failed: %v", err)
|
|
}
|
|
defer encoder.Close()
|
|
|
|
samples := []int32{
|
|
0, // silence
|
|
0x7FFF00, // max positive 16-bit (left-justified in 24-bit)
|
|
-0x800000, // max negative 16-bit (left-justified in 24-bit)
|
|
0x123400, // arbitrary positive value
|
|
-0x567800, // arbitrary negative value
|
|
}
|
|
|
|
output, err := encoder.Encode(samples)
|
|
if err != nil {
|
|
t.Fatalf("Encode() failed: %v", err)
|
|
}
|
|
|
|
expectedSize := len(samples) * 2
|
|
if len(output) != expectedSize {
|
|
t.Errorf("Encode() output size = %d, want %d", len(output), expectedSize)
|
|
}
|
|
|
|
for i, sample := range samples {
|
|
expected := audio.SampleToInt16(sample)
|
|
actual := int16(binary.LittleEndian.Uint16(output[i*2:]))
|
|
if actual != expected {
|
|
t.Errorf("Sample %d: got %d, want %d", i, actual, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPCMEncoder_Encode24Bit(t *testing.T) {
|
|
format := audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 24,
|
|
}
|
|
|
|
encoder, err := NewPCM(format)
|
|
if err != nil {
|
|
t.Fatalf("NewPCM() failed: %v", err)
|
|
}
|
|
defer encoder.Close()
|
|
|
|
samples := []int32{
|
|
0, // silence
|
|
0x7FFFFF, // max positive 24-bit
|
|
-0x800000, // max negative 24-bit
|
|
0x123456, // arbitrary positive value
|
|
-0x567890, // arbitrary negative value
|
|
}
|
|
|
|
output, err := encoder.Encode(samples)
|
|
if err != nil {
|
|
t.Fatalf("Encode() failed: %v", err)
|
|
}
|
|
|
|
expectedSize := len(samples) * 3
|
|
if len(output) != expectedSize {
|
|
t.Errorf("Encode() output size = %d, want %d", len(output), expectedSize)
|
|
}
|
|
|
|
for i, sample := range samples {
|
|
expected := audio.SampleTo24Bit(sample)
|
|
actual := [3]byte{
|
|
output[i*3],
|
|
output[i*3+1],
|
|
output[i*3+2],
|
|
}
|
|
if actual != expected {
|
|
t.Errorf("Sample %d: got %v, want %v", i, actual, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPCMEncoder_Close(t *testing.T) {
|
|
format := audio.Format{
|
|
Codec: "pcm",
|
|
SampleRate: 48000,
|
|
Channels: 2,
|
|
BitDepth: 16,
|
|
}
|
|
|
|
encoder, err := NewPCM(format)
|
|
if err != nil {
|
|
t.Fatalf("NewPCM() failed: %v", err)
|
|
}
|
|
|
|
err = encoder.Close()
|
|
if err != nil {
|
|
t.Errorf("Close() unexpected error = %v", err)
|
|
}
|
|
}
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
|
|
(len(s) > 0 && len(substr) > 0 && indexOf(s, substr) >= 0))
|
|
}
|
|
|
|
func indexOf(s, substr string) int {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|