Adds Alloc(), the ephemeral loopback UDP port grabber the subsystem uses to pick the RTP port it will hand to FFmpeg and then re-bind with core/webrtc.NewSourceOn. Covered by a 100x rebind test. Adds BuildArgs(), which emits the -f rtp output fragments (video on the passed port, audio on port+1) with copy codecs by default and an H.264 baseline / libopus re-encode leg when ForceTranscode is set. Covered by three unit tests.
89 lines
2.3 KiB
Go
89 lines
2.3 KiB
Go
package webrtc
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
appcfg "github.com/datarhei/core/v16/restream/app"
|
|
)
|
|
|
|
func TestBuildArgs_CopyCodecs(t *testing.T) {
|
|
cfg := appcfg.ConfigWebRTC{Enabled: true, VideoPT: 102, AudioPT: 111}
|
|
got := BuildArgs(cfg, 49200)
|
|
|
|
// Must contain -c:v copy and -c:a copy when ForceTranscode is false.
|
|
if !contains(got, "-c:v", "copy") {
|
|
t.Fatalf("expected -c:v copy, got %v", got)
|
|
}
|
|
if !contains(got, "-c:a", "copy") {
|
|
t.Fatalf("expected -c:a copy, got %v", got)
|
|
}
|
|
|
|
// Two UDP addresses, one per track, with port+1 for audio.
|
|
if !any(got, "udp://127.0.0.1:49200?") {
|
|
t.Fatalf("expected video udp on 49200, got %v", got)
|
|
}
|
|
if !any(got, "udp://127.0.0.1:49201?") {
|
|
t.Fatalf("expected audio udp on 49201, got %v", got)
|
|
}
|
|
|
|
// Payload types must be stringified.
|
|
if !contains(got, "-payload_type", "102") {
|
|
t.Fatalf("expected video PT 102, got %v", got)
|
|
}
|
|
if !contains(got, "-payload_type", "111") {
|
|
t.Fatalf("expected audio PT 111, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildArgs_ForceTranscode(t *testing.T) {
|
|
cfg := appcfg.ConfigWebRTC{Enabled: true, VideoPT: 102, AudioPT: 111, ForceTranscode: true}
|
|
got := BuildArgs(cfg, 49200)
|
|
|
|
if !contains(got, "-c:v", "libx264") {
|
|
t.Fatalf("expected -c:v libx264, got %v", got)
|
|
}
|
|
if !contains(got, "-profile:v", "baseline") {
|
|
t.Fatalf("expected baseline profile, got %v", got)
|
|
}
|
|
if !contains(got, "-c:a", "libopus") {
|
|
t.Fatalf("expected -c:a libopus, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildArgs_TwoTrackBoundary(t *testing.T) {
|
|
cfg := appcfg.ConfigWebRTC{Enabled: true, VideoPT: 102, AudioPT: 111}
|
|
got := BuildArgs(cfg, 49200)
|
|
|
|
// The second `-map` marks the start of the audio leg — the split
|
|
// point restream.AppendOutput callers use.
|
|
mapCount := 0
|
|
for _, a := range got {
|
|
if a == "-map" {
|
|
mapCount++
|
|
}
|
|
}
|
|
if mapCount != 2 {
|
|
t.Fatalf("expected exactly 2 -map tokens, got %d in %v", mapCount, got)
|
|
}
|
|
}
|
|
|
|
// contains reports whether the two-token sequence appears consecutively.
|
|
func contains(haystack []string, a, b string) bool {
|
|
for i := 0; i+1 < len(haystack); i++ {
|
|
if haystack[i] == a && haystack[i+1] == b {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// any reports whether any element of haystack starts with prefix.
|
|
func any(haystack []string, prefix string) bool {
|
|
for _, h := range haystack {
|
|
if strings.HasPrefix(h, prefix) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|