From af34cdbd8e4536facc9cfc93c3a6aade8f784a92 Mon Sep 17 00:00:00 2001 From: zarazaex69 Date: Tue, 21 Apr 2026 22:32:01 +0300 Subject: [PATCH] feat: add video-qr-size configuration for videochannel transport --- cmd/olcrtc/main.go | 3 +++ internal/app/session/session.go | 3 +++ internal/client/client.go | 8 ++++++-- internal/link/direct/direct.go | 2 ++ internal/link/link.go | 1 + internal/server/server.go | 5 ++++- internal/transport/transport.go | 1 + internal/transport/videochannel/transport.go | 15 +++++++++++++-- 8 files changed, 33 insertions(+), 5 deletions(-) diff --git a/cmd/olcrtc/main.go b/cmd/olcrtc/main.go index 781c8b4..be78c38 100644 --- a/cmd/olcrtc/main.go +++ b/cmd/olcrtc/main.go @@ -36,6 +36,7 @@ type config struct { videoFPS int videoBitrate string videoHW string + videoQRSize int } func main() { @@ -111,6 +112,7 @@ func parseFlags() config { flag.IntVar(&cfg.videoFPS, "video-fps", 0, "Video frames per second (videochannel only)") flag.StringVar(&cfg.videoBitrate, "video-bitrate", "", "Video bitrate (videochannel only)") flag.StringVar(&cfg.videoHW, "video-hw", "", "Hardware acceleration (none, nvenc)") + flag.IntVar(&cfg.videoQRSize, "video-qr-size", 0, "Video QR code fragment size (videochannel only)") flag.Parse() return cfg @@ -163,6 +165,7 @@ func toSessionConfig(cfg config) session.Config { VideoFPS: cfg.videoFPS, VideoBitrate: cfg.videoBitrate, VideoHW: cfg.videoHW, + VideoQRSize: cfg.videoQRSize, } } diff --git a/internal/app/session/session.go b/internal/app/session/session.go index 4c2a19f..a818096 100644 --- a/internal/app/session/session.go +++ b/internal/app/session/session.go @@ -71,6 +71,7 @@ type Config struct { VideoFPS int VideoBitrate string VideoHW string + VideoQRSize int } // RegisterDefaults registers built-in providers and transports. @@ -202,6 +203,7 @@ func Run(ctx context.Context, cfg Config) error { cfg.VideoFPS, cfg.VideoBitrate, cfg.VideoHW, + cfg.VideoQRSize, ) case "cnc": return client.Run( @@ -220,6 +222,7 @@ func Run(ctx context.Context, cfg Config) error { cfg.VideoFPS, cfg.VideoBitrate, cfg.VideoHW, + cfg.VideoQRSize, ) default: return ErrModeRequired diff --git a/internal/client/client.go b/internal/client/client.go index 6012faf..a53c0c1 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -60,8 +60,9 @@ func Run( videoFPS int, videoBitrate string, videoHW string, + videoQRSize int, ) error { - return RunWithReady(ctx, linkName, transportName, carrierName, roomURL, keyHex, localAddr, dnsServer, socksUser, socksPass, nil, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW) + return RunWithReady(ctx, linkName, transportName, carrierName, roomURL, keyHex, localAddr, dnsServer, socksUser, socksPass, nil, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW, videoQRSize) } // RunWithReady is like Run but accepts a callback that is called when the client is ready. @@ -82,6 +83,7 @@ func RunWithReady( videoFPS int, videoBitrate string, videoHW string, + videoQRSize int, ) error { runCtx, cancel := context.WithCancel(ctx) defer cancel() @@ -109,7 +111,7 @@ func RunWithReady( const linkCount = 1 for i := range linkCount { - if err := c.addLink(runCtx, linkName, transportName, carrierName, roomURL, i, cancel, dnsServer, "", 0, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW); err != nil { + if err := c.addLink(runCtx, linkName, transportName, carrierName, roomURL, i, cancel, dnsServer, "", 0, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW, videoQRSize); err != nil { return fmt.Errorf("addLink failed: %w", err) } } @@ -212,6 +214,7 @@ func (c *Client) addLink( socksProxyPort int, videoWidth, videoHeight, videoFPS int, videoBitrate, videoHW string, + videoQRSize int, ) error { ln, err := link.New(ctx, linkName, link.Config{ Transport: transportName, @@ -227,6 +230,7 @@ func (c *Client) addLink( VideoFPS: videoFPS, VideoBitrate: videoBitrate, VideoHW: videoHW, + VideoQRSize: videoQRSize, }) if err != nil { return fmt.Errorf("failed to create link: %w", err) diff --git a/internal/link/direct/direct.go b/internal/link/direct/direct.go index 058089a..b01d6ec 100644 --- a/internal/link/direct/direct.go +++ b/internal/link/direct/direct.go @@ -27,6 +27,8 @@ func New(ctx context.Context, cfg link.Config) (link.Link, error) { VideoHeight: cfg.VideoHeight, VideoFPS: cfg.VideoFPS, VideoBitrate: cfg.VideoBitrate, + VideoHW: cfg.VideoHW, + VideoQRSize: cfg.VideoQRSize, }) if err != nil { return nil, fmt.Errorf("create transport for direct link: %w", err) diff --git a/internal/link/link.go b/internal/link/link.go index 02c6bf4..a01873f 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -38,6 +38,7 @@ type Config struct { VideoFPS int VideoBitrate string VideoHW string + VideoQRSize int } // Factory creates a link instance. diff --git a/internal/server/server.go b/internal/server/server.go index 7d7e983..984df27 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -79,6 +79,7 @@ func Run( videoFPS int, videoBitrate string, videoHW string, + videoQRSize int, ) error { runCtx, cancel := context.WithCancel(ctx) defer cancel() @@ -103,7 +104,7 @@ func Run( const linkCount = 1 for i := range linkCount { - if err := s.addLink(runCtx, linkName, transportName, carrierName, roomURL, i, cancel, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW); err != nil { + if err := s.addLink(runCtx, linkName, transportName, carrierName, roomURL, i, cancel, videoWidth, videoHeight, videoFPS, videoBitrate, videoHW, videoQRSize); err != nil { return fmt.Errorf("addLink failed: %w", err) } } @@ -189,6 +190,7 @@ func (s *Server) addLink( cancel context.CancelFunc, videoWidth, videoHeight, videoFPS int, videoBitrate, videoHW string, + videoQRSize int, ) error { ln, err := link.New(ctx, linkName, link.Config{ Transport: transportName, @@ -204,6 +206,7 @@ func (s *Server) addLink( VideoFPS: videoFPS, VideoBitrate: videoBitrate, VideoHW: videoHW, + VideoQRSize: videoQRSize, }) if err != nil { return fmt.Errorf("failed to create link: %w", err) diff --git a/internal/transport/transport.go b/internal/transport/transport.go index 0526672..f65cbf9 100644 --- a/internal/transport/transport.go +++ b/internal/transport/transport.go @@ -46,6 +46,7 @@ type Config struct { VideoFPS int VideoBitrate string VideoHW string + VideoQRSize int } // Factory creates a transport instance. diff --git a/internal/transport/videochannel/transport.go b/internal/transport/videochannel/transport.go index 626605c..6393fda 100644 --- a/internal/transport/videochannel/transport.go +++ b/internal/transport/videochannel/transport.go @@ -62,6 +62,7 @@ type streamTransport struct { videoFPS int videoBitrate string videoHW string + videoQRSize int } // New creates a visual videochannel transport backed by a carrier-specific provider. @@ -94,6 +95,11 @@ func New(ctx context.Context, cfg transport.Config) (transport.Transport, error) return nil, fmt.Errorf("create local video track: %w", err) } + qrSize := cfg.VideoQRSize + if qrSize <= 0 { + qrSize = defaultFragmentSize + } + tr := &streamTransport{ stream: stream, track: track, @@ -111,6 +117,7 @@ func New(ctx context.Context, cfg transport.Config) (transport.Transport, error) videoFPS: cfg.VideoFPS, videoBitrate: cfg.VideoBitrate, videoHW: cfg.VideoHW, + videoQRSize: qrSize, } if err := stream.AddTrack(track); err != nil { @@ -156,7 +163,7 @@ func (p *streamTransport) Send(data []byte) error { seq := p.nextSeq.Add(1) crc := crc32.ChecksumIEEE(data) - fragments := fragmentPayload(data, defaultFragmentSize) + fragments := fragmentPayload(data, p.videoQRSize) waiter := make(chan uint32, 1) p.ackMu.Lock() @@ -235,11 +242,15 @@ func (p *streamTransport) CanSend() bool { // Features describes the current videochannel transport semantics. func (p *streamTransport) Features() transport.Features { + maxPayload := defaultMaxPayloadSize + if p.videoQRSize*64 > maxPayload { + maxPayload = p.videoQRSize * 64 + } return transport.Features{ Reliable: true, Ordered: true, MessageOriented: true, - MaxPayloadSize: defaultMaxPayloadSize, + MaxPayloadSize: maxPayload, } }