This commit is contained in:
@@ -17,8 +17,10 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -760,6 +762,34 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
|
||||
if drops := session.Telemetry().MediaDrops; drops < 2 {
|
||||
t.Fatalf("stale FEC eviction drops = %d, want at least 2", drops)
|
||||
}
|
||||
beforeIngress := session.mediaIngress.Load()
|
||||
beforeDrops := session.mediaDrops.Load()
|
||||
if _, err := videoServer.WriteToUDP(make([]byte, apolloMediaMaximumPacket+2), videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
marker := []byte{0xde, 0xad, 0xbe, 0xef}
|
||||
markerPayload := make([]byte, apolloVideoShardPayloadSize)
|
||||
markerPayload[0], markerPayload[3] = 0x01, 0x01
|
||||
binary.LittleEndian.PutUint16(markerPayload[4:6], uint16(8+len(marker)))
|
||||
copy(markerPayload[8:], marker)
|
||||
markerPacket := sourceEncryptVideoRaw(t, key, sourceShapedVideoRaw(44, 103, 103, 0x07, 1, 0, 0, markerPayload), "0123456789dV")
|
||||
if _, err := videoServer.WriteToUDP(markerPacket, videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case media := <-session.Video():
|
||||
if !bytes.Equal(media.Payload, marker) {
|
||||
t.Fatalf("post-oversize marker relay = %x, want %x", media.Payload, marker)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("post-oversize marker was not relayed")
|
||||
}
|
||||
if got := session.mediaIngress.Load() - beforeIngress; got != 1 {
|
||||
t.Fatalf("post-oversize video ingress = %d, want 1 valid marker", got)
|
||||
}
|
||||
if got := session.mediaDrops.Load(); got != beforeDrops {
|
||||
t.Fatalf("post-oversize video drops = %d, want unchanged %d", got, beforeDrops)
|
||||
}
|
||||
terminateCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
if err := session.Terminate(terminateCtx); err != nil {
|
||||
@@ -767,6 +797,166 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeApolloVideoIngressSaturationIsBoundedAndAccounted(t *testing.T) {
|
||||
if nativeApolloVideoIngressSlots != 2048 || nativeApolloVideoReadBuffer != 2_195_456 {
|
||||
t.Fatalf("video ingress bounds = %d slots/%d bytes, want 2048/2195456", nativeApolloVideoIngressSlots, nativeApolloVideoReadBuffer)
|
||||
}
|
||||
ingress := newNativeApolloVideoIngress()
|
||||
if len(ingress.slots) != 2048 || len(ingress.free) != 2048 || cap(ingress.ready) != 2048 || len(ingress.slots[0].packet) != apolloMediaMaximumPacket+1 {
|
||||
t.Fatalf("video ingress pool = slots:%d free:%d ready-cap:%d packet:%d",
|
||||
len(ingress.slots), len(ingress.free), cap(ingress.ready), len(ingress.slots[0].packet))
|
||||
}
|
||||
|
||||
key := []byte("0123456789abcdef")
|
||||
session, audioServer, videoServer := newNativeApolloMediaTestSession(t, key)
|
||||
defer audioServer.Close()
|
||||
defer videoServer.Close()
|
||||
blockCtx, cancelBlock := context.WithCancel(context.Background())
|
||||
defer cancelBlock()
|
||||
blocked := make(chan struct{})
|
||||
release := make(chan struct{})
|
||||
var releaseOnce sync.Once
|
||||
releaseAEAD := func() { releaseOnce.Do(func() { close(release) }) }
|
||||
defer releaseAEAD()
|
||||
session.media.aead = &qualificationBlockingAEAD{
|
||||
AEAD: session.media.aead, ctx: blockCtx, blocked: blocked, release: release,
|
||||
}
|
||||
go session.readUDPMedia()
|
||||
|
||||
packet := sourceShapedEncryptedVideoPacket(t, key, []byte{1})
|
||||
if _, err := videoServer.WriteToUDP(packet, session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case <-blocked:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("video processor did not block")
|
||||
}
|
||||
waitIngress := func(want uint64) {
|
||||
t.Helper()
|
||||
deadline := time.NewTimer(time.Second)
|
||||
defer deadline.Stop()
|
||||
for session.mediaIngress.Load() < want {
|
||||
select {
|
||||
case <-deadline.C:
|
||||
t.Fatalf("video ingress = %d, want at least %d", session.mediaIngress.Load(), want)
|
||||
default:
|
||||
runtime.Gosched()
|
||||
}
|
||||
}
|
||||
}
|
||||
waitIngress(1)
|
||||
const overflow = 33
|
||||
sent := uint64(1)
|
||||
for remaining := nativeApolloVideoIngressSlots - 1 + overflow; remaining > 0; {
|
||||
batch := min(32, remaining)
|
||||
for range batch {
|
||||
if _, err := videoServer.WriteToUDP([]byte{1}, session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
sent += uint64(batch)
|
||||
waitIngress(sent)
|
||||
remaining -= batch
|
||||
}
|
||||
if got := session.mediaDrops.Load(); got != overflow {
|
||||
t.Fatalf("saturated video ingress drops = %d, want %d", got, overflow)
|
||||
}
|
||||
|
||||
session.quiesceMedia()
|
||||
cancelBlock()
|
||||
select {
|
||||
case <-session.readDone:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("video ingress workers did not stop")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeApolloTerminateStopsActiveVideoDrainAndProcessor(t *testing.T) {
|
||||
key := []byte("0123456789abcdef")
|
||||
session, audioServer, videoServer := newNativeApolloMediaTestSession(t, key)
|
||||
defer audioServer.Close()
|
||||
defer videoServer.Close()
|
||||
blockCtx, cancelBlock := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancelBlock)
|
||||
blocked := make(chan struct{})
|
||||
session.media.aead = &qualificationBlockingAEAD{
|
||||
AEAD: session.media.aead, ctx: blockCtx, blocked: blocked, release: make(chan struct{}),
|
||||
}
|
||||
go session.readUDPMedia()
|
||||
if _, err := videoServer.WriteToUDP(sourceShapedEncryptedVideoPacket(t, key, []byte{1}), session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case <-blocked:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("video processor did not block")
|
||||
}
|
||||
|
||||
terminateCtx, cancelTerminate := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancelTerminate()
|
||||
terminated := make(chan error, 1)
|
||||
go func() { terminated <- session.Terminate(terminateCtx) }()
|
||||
cancelBlock()
|
||||
if err := <-terminated; err != nil {
|
||||
t.Fatalf("Terminate() error = %v", err)
|
||||
}
|
||||
select {
|
||||
case <-session.readDone:
|
||||
default:
|
||||
t.Fatal("Terminate returned before video drain and processor stopped")
|
||||
}
|
||||
select {
|
||||
case _, ok := <-session.Video():
|
||||
if ok {
|
||||
t.Fatal("video channel remained open after worker shutdown")
|
||||
}
|
||||
default:
|
||||
t.Fatal("video channel was not closed after worker shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
func newNativeApolloMediaTestSession(t *testing.T, key []byte) (*nativeApolloSession, *net.UDPConn, *net.UDPConn) {
|
||||
t.Helper()
|
||||
audioServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
videoServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
|
||||
if err != nil {
|
||||
_ = audioServer.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
audioClient, err := net.DialUDP("udp", nil, audioServer.LocalAddr().(*net.UDPAddr))
|
||||
if err != nil {
|
||||
_ = audioServer.Close()
|
||||
_ = videoServer.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
videoClient, err := net.DialUDP("udp", nil, videoServer.LocalAddr().(*net.UDPAddr))
|
||||
if err != nil {
|
||||
_ = audioClient.Close()
|
||||
_ = audioServer.Close()
|
||||
_ = videoServer.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
session := newNativeApolloSession("session-video-ingress")
|
||||
session.media, err = newApolloMediaCodec(key, 1)
|
||||
if err != nil {
|
||||
_ = audioClient.Close()
|
||||
_ = videoClient.Close()
|
||||
_ = audioServer.Close()
|
||||
_ = videoServer.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
session.audioConn, session.videoConn = audioClient, videoClient
|
||||
t.Cleanup(func() {
|
||||
_ = audioClient.Close()
|
||||
_ = videoClient.Close()
|
||||
})
|
||||
return session, audioServer, videoServer
|
||||
}
|
||||
|
||||
func TestNativeApolloTerminateReleasesPressedProviderInput(t *testing.T) {
|
||||
server, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user