From 552151fece0f398152112e35cb2c32fc0550e2c6 Mon Sep 17 00:00:00 2001 From: zarazaex69 Date: Wed, 27 May 2026 10:55:37 +0300 Subject: [PATCH] fix(videochannel): force VP8 keyframes and drop bad frames --- go.mod | 2 +- go.sum | 4 +-- internal/transport/videochannel/gocodec.go | 10 +++--- internal/transport/videochannel/transport.go | 33 ++++++-------------- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 9cfce72..36deac0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/openlibrecommunity/olcrtc go 1.26.3 require ( - codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f + codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/livekit/protocol v1.46.0 diff --git a/go.sum b/go.sum index 131aebf..eb37156 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MG cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f h1:amyzfF9+4jCUKJndW336YHbj3FiaWs/qkJqOgUyreCA= -codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f/go.mod h1:ooInikVAZhJE+m+gHIekq52ZFkUPcCZAvY4u/m2M/V0= +codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2 h1:u7QorW08YOZGj86cubeGpiwm+d0tMKa0e7syiBkO2eo= +codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2/go.mod h1:ooInikVAZhJE+m+gHIekq52ZFkUPcCZAvY4u/m2M/V0= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= diff --git a/internal/transport/videochannel/gocodec.go b/internal/transport/videochannel/gocodec.go index 6303c64..0ef463d 100644 --- a/internal/transport/videochannel/gocodec.go +++ b/internal/transport/videochannel/gocodec.go @@ -20,8 +20,10 @@ type goEncoder struct { } func newGoEncoder(width, height, _ int) *goEncoder { + enc := vp8.NewEncoder(width, height, 63) + enc.SetKeyInterval(1) return &goEncoder{ - enc: vp8.NewEncoder(width, height, 10), + enc: enc, width: width, height: height, frameSize: width * height, @@ -74,12 +76,10 @@ func (d *goDecoder) PushSample(sample []byte) error { } frame, err := d.dec.Decode(sample) if err != nil { - // Inter-frame arrived before any keyframe (e.g. SFU started forwarding - // mid-GOP). Drop silently; the next keyframe will reset the reference. if errors.Is(err, vp8.ErrNoReference) { - return nil + return nil // skip inter-frames until keyframe arrives } - return fmt.Errorf("vp8 decode: %w", err) + return nil // skip undecodable frames (e.g. from other participants) } gray := frame.Grayscale() select { diff --git a/internal/transport/videochannel/transport.go b/internal/transport/videochannel/transport.go index 1c3d329..ed9abcf 100644 --- a/internal/transport/videochannel/transport.go +++ b/internal/transport/videochannel/transport.go @@ -88,9 +88,6 @@ type streamTransport struct { remoteRole byte bindingToken uint32 runCtx context.Context //nolint:containedctx,lll // long-lived context drives idle-frame loops bound to this transport's lifetime - - idleFrame []byte - idleFrameMu sync.Mutex } // New creates a visual videochannel transport backed by a carrier engine. @@ -388,28 +385,18 @@ func (p *streamTransport) Features() transport.Features { } func (p *streamTransport) writeIdleFrame(enc *goEncoder, frameDuration time.Duration) { - p.idleFrameMu.Lock() - cached := p.idleFrame - p.idleFrameMu.Unlock() - - if cached == nil { - rawFrame, err := p.renderFrame(nil) - if err != nil { - logger.Debugf("videochannel render idle error: %v", err) - return - } - sample, err := enc.EncodeFrame(rawFrame) - if err != nil { - logger.Warnf("videochannel encoder idle error: %v", err) - return - } - p.idleFrameMu.Lock() - p.idleFrame = sample - p.idleFrameMu.Unlock() - cached = sample + rawFrame, err := p.renderFrame(nil) + if err != nil { + logger.Debugf("videochannel render idle error: %v", err) + return + } + sample, err := enc.EncodeFrame(rawFrame) + if err != nil { + logger.Warnf("videochannel encoder idle error: %v", err) + return } - _ = p.track.WriteSample(media.Sample{Data: cached, Duration: frameDuration}) + _ = p.track.WriteSample(media.Sample{Data: sample, Duration: frameDuration}) } func (p *streamTransport) writePayloadFrame(enc *goEncoder, payload []byte, frameDuration time.Duration) {