From f6f8d61805aa96ff4dc0f3d716268ef81fb10646 Mon Sep 17 00:00:00 2001 From: Benjamin Pracht Date: Thu, 27 Aug 2026 16:24:11 -0700 Subject: [PATCH 1/4] Add UDP URL pull support behind a config flag Support udp:// URLs in the URL pull source using a gstreamer udpsrc element, gated by the enable_udp_url_pull service config option. Add a multicast_interface option to pick the network interface to join multicast groups on, and log udpsrc stats alongside the other input sources. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/config/config.go | 3 +++ pkg/media/urlpull/source.go | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 15bba80d..2bbf2f38 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -61,6 +61,9 @@ type ServiceConfig struct { Logging logger.Config `yaml:"logging"` Development bool `yaml:"development"` PSRPCSkipClaim bool `yaml:"psrpc_skip_claim,omitempty"` // Lets psrpc servers skip the claim handshake on queue rpcs + EnableUDPURLPull bool `yaml:"enable_udp_url_pull,omitempty"` + // Network interface to join multicast groups on for UDP url pull. Empty means let the OS decide. + MulticastInterface string `yaml:"multicast_interface,omitempty"` // Used for WHIP transport RTCConfig rtcconfig.RTCConfig `yaml:"rtc_config"` diff --git a/pkg/media/urlpull/source.go b/pkg/media/urlpull/source.go index 867db5de..9334cd5c 100644 --- a/pkg/media/urlpull/source.go +++ b/pkg/media/urlpull/source.go @@ -22,9 +22,10 @@ import ( "github.com/frostbyte73/core" "github.com/go-gst/go-gst/gst" + "github.com/livekit/protocol/logger" + "github.com/livekit/ingress/pkg/errors" "github.com/livekit/ingress/pkg/params" - "github.com/livekit/protocol/logger" ) var ( @@ -85,6 +86,31 @@ func NewURLSource(_ context.Context, p *params.Params) (*URLSource, error) { } } } + } else if p.Config.EnableUDPURLPull && strings.HasPrefix(p.Url, "udp://") { + elem, err = gst.NewElement("udpsrc") + if err != nil { + return nil, err + } + err = elem.SetProperty("uri", p.Url) + if err != nil { + return nil, err + } + + if p.Config.MulticastInterface != "" { + err = elem.SetProperty("multicast-iface", p.Config.MulticastInterface) + if err != nil { + return nil, err + } + } + + printStats = func() { + str, _ := elem.GetProperty("stats") + if str != nil { + if v, ok := str.(*gst.Structure); ok { + logger.Infow("UDP input stats", "stats", v.String()) + } + } + } } else { return nil, errors.ErrUnsupportedURLFormat } From 4d6eb945dd1604691934afc7b02121f82cc7c8e4 Mon Sep 17 00:00:00 2001 From: Benjamin Pracht Date: Thu, 27 Aug 2026 16:33:19 -0700 Subject: [PATCH 2/4] Fix static checks --- pkg/media/urlpull/source.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/media/urlpull/source.go b/pkg/media/urlpull/source.go index 9334cd5c..6b0bb844 100644 --- a/pkg/media/urlpull/source.go +++ b/pkg/media/urlpull/source.go @@ -86,7 +86,7 @@ func NewURLSource(_ context.Context, p *params.Params) (*URLSource, error) { } } } - } else if p.Config.EnableUDPURLPull && strings.HasPrefix(p.Url, "udp://") { + } else if p.EnableUDPURLPull && strings.HasPrefix(p.Url, "udp://") { elem, err = gst.NewElement("udpsrc") if err != nil { return nil, err @@ -96,8 +96,8 @@ func NewURLSource(_ context.Context, p *params.Params) (*URLSource, error) { return nil, err } - if p.Config.MulticastInterface != "" { - err = elem.SetProperty("multicast-iface", p.Config.MulticastInterface) + if p.MulticastInterface != "" { + err = elem.SetProperty("multicast-iface", p.MulticastInterface) if err != nil { return nil, err } From e5c702271ae234b9fa82a6dd378aa4e2255e4965 Mon Sep 17 00:00:00 2001 From: Benjamin Pracht Date: Thu, 27 Aug 2026 16:41:22 -0700 Subject: [PATCH 3/4] Drop the no-op stats logging for UDP url pull udpsrc has no stats property, so the periodic GetProperty("stats") call always failed and logged nothing. Leave printStats unset for UDP, which makes Start skip the ticker goroutine entirely. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/media/urlpull/source.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pkg/media/urlpull/source.go b/pkg/media/urlpull/source.go index 6b0bb844..b676ca11 100644 --- a/pkg/media/urlpull/source.go +++ b/pkg/media/urlpull/source.go @@ -103,14 +103,7 @@ func NewURLSource(_ context.Context, p *params.Params) (*URLSource, error) { } } - printStats = func() { - str, _ := elem.GetProperty("stats") - if str != nil { - if v, ok := str.(*gst.Structure); ok { - logger.Infow("UDP input stats", "stats", v.String()) - } - } - } + // udpsrc doesn't expose a stats property, so leave printStats unset } else { return nil, errors.ErrUnsupportedURLFormat } From 03b6610f2f85681ca43ded2bd788166bd224fd12 Mon Sep 17 00:00:00 2001 From: Benjamin Pracht Date: Thu, 27 Aug 2026 17:18:02 -0700 Subject: [PATCH 4/4] Document the new UDP url pull config entries in the README Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ae5647c2..5466e5ae 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ rtmp_port: port to listen to incoming RTMP connection on (default 1935) whip_port: port to listen to incoming WHIP calls on (default 8080) http_relay_port: port used to relay data from the main service process to the per ingress handler process (default 9090) rtc_config: configuration for ICE and other RTC related settings, same settings livekit-server RTC configuration. Used for WHIP. +enable_udp_url_pull: allow URL pull ingresses to pull from udp:// urls (default false) +multicast_interface: network interface to join multicast groups on for UDP url pull. Empty lets the OS decide # cpu costs for various Ingress types with their default values cpu_cost: