test(gateway): pace qualification video source
Verify Data Plane / gateway (push) Failing after 1m30s
Verify Data Plane / gateway (push) Failing after 1m30s
This commit is contained in:
@@ -39,15 +39,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
qualificationToolVersion = "versevdi-gateway-qualification/v6"
|
||||
qualificationImpairmentQueuePackets = nativeApolloVideoQueuePackets
|
||||
qualificationImpairmentMaxPackets = 100_000
|
||||
qualificationImpairmentPacketCount = 10_000
|
||||
qualificationProcessingLimit = 5 * time.Millisecond
|
||||
qualificationImpairmentSeed uint64 = 0x3c6a11ce
|
||||
qualificationClockOverheadMethod = "median of 1000 batches of 100 monotonic time reads"
|
||||
qualificationGatewayCPUScope = "isolated gateway subprocess; bounded recorder/control included, fixture and client driver excluded"
|
||||
qualificationResourceMethod = "RUSAGE_SELF user+system CPU; runtime/metrics heap objects, allocated objects/bytes, and live goroutines sampled once per second"
|
||||
qualificationToolVersion = "versevdi-gateway-qualification/v7"
|
||||
qualificationImpairmentQueuePackets = nativeApolloVideoQueuePackets
|
||||
qualificationImpairmentMaxPackets = 100_000
|
||||
qualificationImpairmentPacketCount = 10_000
|
||||
qualificationProcessingLimit = 5 * time.Millisecond
|
||||
qualificationImpairmentSeed uint64 = 0x3c6a11ce
|
||||
qualificationClockOverheadMethod = "median of 1000 batches of 100 monotonic time reads"
|
||||
qualificationGatewayCPUScope = "isolated gateway subprocess; bounded recorder/control included, fixture and client driver excluded"
|
||||
qualificationResourceMethod = "RUSAGE_SELF user+system CPU; runtime/metrics heap objects, allocated objects/bytes, and live goroutines sampled once per second"
|
||||
qualificationApolloVideoRateBitsPerSecond = 1_000_000_000 * 80 / 100
|
||||
qualificationApolloVideoBatchBytes = 64 * 1024
|
||||
qualificationApolloVideoBatchPackets = 64
|
||||
)
|
||||
|
||||
type qualificationMediaProfile struct {
|
||||
@@ -425,6 +428,8 @@ type qualificationApolloFixture struct {
|
||||
closeOnce sync.Once
|
||||
sentPackets atomic.Uint64
|
||||
work protocol.ProviderSessionWork
|
||||
videoPaceMu sync.Mutex
|
||||
videoNext time.Time
|
||||
|
||||
controlImpairmentMu sync.Mutex
|
||||
controlRTT time.Duration
|
||||
@@ -754,15 +759,76 @@ func (f *qualificationApolloFixture) sendVideo(ctx context.Context, packets [][]
|
||||
}
|
||||
}
|
||||
remote := f.videoRemote.Load()
|
||||
for _, packet := range packets {
|
||||
if _, err := f.video.WriteToUDP(packet, remote); err != nil {
|
||||
return err
|
||||
}
|
||||
f.sentPackets.Add(1)
|
||||
if len(packets) == 0 {
|
||||
return nil
|
||||
}
|
||||
packetsPerMillisecond, batchSize := qualificationApolloVideoPacing(len(packets[0]))
|
||||
if packetsPerMillisecond == 0 || batchSize == 0 {
|
||||
return ErrProviderMalformed
|
||||
}
|
||||
|
||||
f.videoPaceMu.Lock()
|
||||
defer f.videoPaceMu.Unlock()
|
||||
frameStart := time.Now()
|
||||
if f.videoNext.After(frameStart) {
|
||||
frameStart = f.videoNext
|
||||
}
|
||||
framePackets, groupPackets := 0, 0
|
||||
for batchStart := 0; batchStart < len(packets); batchStart += batchSize {
|
||||
if framePackets == 0 || groupPackets >= packetsPerMillisecond {
|
||||
due := frameStart.Add(time.Millisecond * time.Duration(framePackets) / time.Duration(packetsPerMillisecond))
|
||||
if err := qualificationWaitContext(ctx, due); err != nil {
|
||||
return err
|
||||
}
|
||||
groupPackets = 0
|
||||
}
|
||||
batchEnd := min(batchStart+batchSize, len(packets))
|
||||
for _, packet := range packets[batchStart:batchEnd] {
|
||||
if len(packet) != len(packets[0]) {
|
||||
return ErrProviderMalformed
|
||||
}
|
||||
if _, err := f.video.WriteToUDP(packet, remote); err != nil {
|
||||
return err
|
||||
}
|
||||
f.sentPackets.Add(1)
|
||||
}
|
||||
currentBatch := batchEnd - batchStart
|
||||
framePackets += currentBatch
|
||||
groupPackets += currentBatch
|
||||
}
|
||||
f.videoNext = frameStart.Add(time.Millisecond * time.Duration(framePackets) / time.Duration(packetsPerMillisecond))
|
||||
return nil
|
||||
}
|
||||
|
||||
func qualificationApolloVideoPacing(packetBytes int) (packetsPerMillisecond, batchSize int) {
|
||||
if packetBytes <= 0 {
|
||||
return 0, 0
|
||||
}
|
||||
packetsPerMillisecond = qualificationApolloVideoRateBitsPerSecond / 1000 / packetBytes / 8
|
||||
batchSize = min(qualificationApolloVideoBatchBytes/packetBytes, qualificationApolloVideoBatchPackets)
|
||||
return packetsPerMillisecond, batchSize
|
||||
}
|
||||
|
||||
func qualificationWaitContext(ctx context.Context, due time.Time) error {
|
||||
delay := time.Until(due)
|
||||
if delay <= 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-timer.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (f *qualificationApolloFixture) streamKey() ([]byte, error) {
|
||||
key := f.key.Load()
|
||||
if key == nil || len(*key) != 16 {
|
||||
|
||||
Reference in New Issue
Block a user