144 lines
3.4 KiB
Go
144 lines
3.4 KiB
Go
package transcode_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"os/exec"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.senan.xyz/gonic/transcode"
|
|
)
|
|
|
|
var testProfile = transcode.PCM16le
|
|
|
|
const (
|
|
// assuming above profile is 48kHz 16bit stereo
|
|
sampleRate = 48_000
|
|
bytesPerSample = 2
|
|
numChannels = 2
|
|
)
|
|
|
|
const bytesPerSec = sampleRate * bytesPerSample * numChannels
|
|
|
|
func TestMain(m *testing.M) {
|
|
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
|
return // no ffmpeg, skip these tests
|
|
}
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
// TestTranscode starts a web server that transcodes a 5s FLAC file to PCM audio. A client
|
|
// consumes the result over a 5 second period.
|
|
func TestTranscode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testFile := "testdata/5s.flac"
|
|
testFileLen := 5
|
|
|
|
tr := transcode.NewFFmpegTranscoder()
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.NoError(t, tr.Transcode(r.Context(), testProfile, testFile, w))
|
|
w.(http.Flusher).Flush()
|
|
}))
|
|
defer server.Close()
|
|
|
|
resp, err := server.Client().Get(server.URL)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
var buf bytes.Buffer
|
|
for {
|
|
n, err := io.Copy(&buf, io.LimitReader(resp.Body, bytesPerSec))
|
|
require.NoError(t, err)
|
|
if n == 0 {
|
|
break
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
// we should have 5 seconds of PCM data
|
|
require.Equal(t, testFileLen*bytesPerSec, buf.Len())
|
|
}
|
|
|
|
// TestTranscodeWithSeek starts a web server that transcodes a 5s FLAC file to PCM audio, but with a 2 second offset.
|
|
// A client consumes the result over a 3 second period.
|
|
func TestTranscodeWithSeek(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testFile := "testdata/5s.flac"
|
|
testFileLen := 5
|
|
|
|
seekSecs := 2
|
|
profile := transcode.WithSeek(testProfile, time.Duration(seekSecs)*time.Second)
|
|
|
|
tr := transcode.NewFFmpegTranscoder()
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.NoError(t, tr.Transcode(r.Context(), profile, testFile, w))
|
|
w.(http.Flusher).Flush()
|
|
}))
|
|
defer server.Close()
|
|
|
|
resp, err := server.Client().Get(server.URL)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
var buf bytes.Buffer
|
|
for {
|
|
n, err := io.Copy(&buf, io.LimitReader(resp.Body, bytesPerSec))
|
|
require.NoError(t, err)
|
|
if n == 0 {
|
|
break
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
// since we seeked 2 seconds, we should have 5-2 = 3 seconds of PCM data
|
|
require.Equal(t, (testFileLen-seekSecs)*bytesPerSec, buf.Len())
|
|
}
|
|
|
|
func TestCachingParallelism(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var realTranscodeCount atomic.Uint64
|
|
transcoder := callbackTranscoder{
|
|
transcoder: transcode.NewFFmpegTranscoder(),
|
|
callback: func() { realTranscodeCount.Add(1) },
|
|
}
|
|
|
|
cacheTranscoder := transcode.NewCachingTranscoder(transcoder, t.TempDir())
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
var buf bytes.Buffer
|
|
require.NoError(t, cacheTranscoder.Transcode(context.Background(), transcode.PCM16le, "testdata/5s.flac", &buf))
|
|
require.Equal(t, 5*bytesPerSec, buf.Len())
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
require.Equal(t, 1, int(realTranscodeCount.Load()))
|
|
}
|
|
|
|
type callbackTranscoder struct {
|
|
transcoder transcode.Transcoder
|
|
callback func()
|
|
}
|
|
|
|
func (ct callbackTranscoder) Transcode(ctx context.Context, profile transcode.Profile, in string, out io.Writer) error {
|
|
ct.callback()
|
|
return ct.transcoder.Transcode(ctx, profile, in, out)
|
|
}
|