From 1427c0d3c7caa142455977788a2677f0d2d1ba1e Mon Sep 17 00:00:00 2001 From: zarazaex69 Date: Thu, 28 May 2026 05:54:18 +0300 Subject: [PATCH] fix(videochannel): increase timeouts to handle SFU renegotiation delays --- internal/e2e/stress_test.go | 10 ++++++---- internal/e2e/tunnel_test.go | 10 +++++----- internal/transport/videochannel/transport.go | 4 ++-- internal/transport/videochannel/transport_unit_test.go | 4 ++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/internal/e2e/stress_test.go b/internal/e2e/stress_test.go index fb1b9fd..c966949 100644 --- a/internal/e2e/stress_test.go +++ b/internal/e2e/stress_test.go @@ -212,10 +212,12 @@ func streamPatternForDuration(conn net.Conn, duration time.Duration, chunkSize i if chunkSize <= 0 { chunkSize = 4096 } - // Per-chunk roundtrip deadline. Slow transports (videochannel) can - // take seconds+ per chunk in practice; 15s gives ample margin - // without making genuine stalls hang forever. - const chunkTimeout = 15 * time.Second + // Per-chunk roundtrip deadline. Videochannel uses per-fragment acks + // with up to 20 retransmit attempts; during SFU renegotiation frames + // can be lost for several seconds, triggering the full retransmit + // cycle (~40s worst case). 45s covers that while still catching + // genuine stalls within a reasonable time. + const chunkTimeout = 45 * time.Second start := time.Now() deadline := start.Add(duration) diff --git a/internal/e2e/tunnel_test.go b/internal/e2e/tunnel_test.go index 3e4b18a..2113594 100644 --- a/internal/e2e/tunnel_test.go +++ b/internal/e2e/tunnel_test.go @@ -933,12 +933,12 @@ func e2eTransportOptions(transportName string) transport.Options { switch transportName { case "videochannel": return videochannel.Options{ - Width: 320, - Height: 320, - FPS: 25, - Bitrate: "500k", + Width: 1080, + Height: 1080, + FPS: 10, + Bitrate: "1000k", HW: videoHWNone, - QRSize: 256, + QRSize: 512, QRRecovery: "low", Codec: "qrcode", TileModule: 4, diff --git a/internal/transport/videochannel/transport.go b/internal/transport/videochannel/transport.go index 2b41a46..ed9abcf 100644 --- a/internal/transport/videochannel/transport.go +++ b/internal/transport/videochannel/transport.go @@ -23,7 +23,7 @@ import ( const ( defaultMaxPayloadSize = 16 * 1024 defaultFragmentSize = 256 - defaultAckTimeout = 300 * time.Millisecond + defaultAckTimeout = 1 * time.Second defaultFrameInterval = 40 * time.Millisecond defaultConnectTimeout = 30 * time.Second maxSendAttempts = 20 @@ -301,7 +301,7 @@ func perAttemptAckTimeout(fragments, fps int) time.Duration { fps = 25 } frameInterval := time.Second / time.Duration(fps) - estimated := time.Duration(fragments) * frameInterval * 2 + estimated := time.Duration(fragments) * frameInterval * 3 if estimated < defaultAckTimeout { return defaultAckTimeout } diff --git a/internal/transport/videochannel/transport_unit_test.go b/internal/transport/videochannel/transport_unit_test.go index e1f9003..25169fc 100644 --- a/internal/transport/videochannel/transport_unit_test.go +++ b/internal/transport/videochannel/transport_unit_test.go @@ -262,8 +262,8 @@ func TestPerAttemptAckTimeoutScalesWithFragments(t *testing.T) { t.Fatalf("perAttemptAckTimeout(2,25) = %v, want %v", got, defaultAckTimeout) } - // 16 fragments @ 25 FPS: 16 * 40ms * 2 = 1280ms. - if got, want := perAttemptAckTimeout(16, 25), 1280*time.Millisecond; got != want { + // 16 fragments @ 25 FPS: 16 * 40ms * 3 = 1920ms. + if got, want := perAttemptAckTimeout(16, 25), 1920*time.Millisecond; got != want { t.Fatalf("perAttemptAckTimeout(16,25) = %v, want %v", got, want) }