stunner

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 30 Imported by: 0

README

STUNner
Discord Go Reference

STUNner: The Kubernetes real-time media gateway

Ever wondered how to deploy your real-time communications infrastructure into the cloud? Frightened away by the complexities of Kubernetes container networking, and the surprising ways in which it may interact with your media streams? Indeed, Kubernetes was built for HTTP/TCP, while WebRTC, VoIP and live video run over UDP protocols that simply do not fit into the cloud-native model. The usual answer is host networking and thousands of open UDP ports, just to get a public address for every media endpoint.

STUNner is a media gateway with a simple goal: make real-time media just another Kubernetes workload. It exposes a single external port to ingest all media streams into the cluster in a standards-compliant way and relay them to your media services running in ordinary, unprivileged Kubernetes pods. The intention is to remove all operational friction that hinders Kubernetes media services today.

STUNner can ingest essentially all protocols of the media streaming landscape:

  • WebRTC: a STUN/TURN gateway for browsers and WebRTC clients to reach your media servers (LiveKit, Janus, Jitsi, mediasoup, Elixir WebRTC, and the like), with full browser compatibility and no change to your existing WebRTC codebase.
  • SIP and RTP (beta): a SIP and RTP gateway for SIP trunks, so carriers can deliver phone calls to SIP servers like LiveKit SIP running in the cluster, with no host networking and no public RTP port range.
  • SRT (beta): a stream router for live video contribution, so encoders, drones and cameras publish their SRT streams to media servers like MediaMTX running in the cluster, and the publisher and the readers of every stream meet on the same pod behind a single UDP port.
  • RTSP (beta): viewers watch IP cameras through a restreamer in the cluster over RTSP interleaved over TCP.
  • Plain UDP and TCP: any UDP or TCP service gets a public port with no per-pod Services.

STUNner implements the Kubernetes Gateway API, so you configure it with the same YAML manifests as the rest of your workload.

Table of Contents

  1. Description
  2. Features
  3. Getting started
  4. Usage
  5. Documentation

Description

Real-time media lacks a virtualization story: there is no easy way to deploy a WebRTC media server or a SIP gateway into Kubernetes and benefit from the resiliency, scalability, and high availability features we have come to expect from modern network services. WebRTC deployments have to rely on public STUN servers and hosted TURN services to connect clients behind a NAT, and SIP deployments end up on dedicated hosts with public address and wide exposed RTP port ranges.

The main goal of STUNner is to allow anyone to deploy their own real-time media infrastructure into Kubernetes, without relying on any external service other than the cloud provider's standard hosted Kubernetes offering. In a typical deployment, STUNner acts as a gateway that ingests WebRTC media into the cluster through a public STUN/TURN server (media-plane model), connects SIP trunks to cluster-bound SIP servers (SIP model), or as a stream router in front of a pool of SRT media servers (SRT model). Your application servers, media servers, SIP servers and streaming servers then run in ordinary Kubernetes pods, managed, scaled, monitored and troubleshot in exactly the same way as any other Kubernetes workload. STUNner can act as a standalone STUN/TURN server that WebRTC clients and media servers use for NAT traversal (headless model).

STUNner media gateway landscape

Don't worry about the performance implications of processing all your media through a gateway: STUNner is fast, it is co-located with your media servers so you don't pay the round-trip time to a far-away relay, and it scales like any other Kubernetes service.

STUNner is open source: the dataplane, the gateway operator, the authentication service, the Helm chart and the tools are all public on GitHub. The official STUNner images and the stunner/stunner Helm chart are built by l7mp.io from the same code, plus a few premium additions. Without a customer key you get the free tier: unlimited TURN Gateways and connections, and a limited use of the SIP/RTP and SRT gateways and of STUNner's industry-leading Linux/eBPF kernel offload engine. The member tier, aimed at small and medium-scale operations, unlocks a number of premium features and higher limits. The fully featured enterprise tier, optimized for large-scale deployments, has no limits on the Gateways, the sessions and the offloaded flows. See here for the limits and pricing at each tier, and on how to purchase a license. Note that SIP/RTP and SRT are in beta and there is absolutely no support at any tier: use the beta features at your own risk.

Features

Kubernetes has been designed and optimized for the typical HTTP/TCP Web workload, which makes streaming workloads, and especially UDP media, feel like a foreign citizen. STUNner aims to change this, by a single public gateway port for ingesting all media traffic into a Kubernetes cluster in a controlled and standards-compliant way: TURN for WebRTC, SIP and RTP for VoIP, SRT for live video contribution, plain UDP and TCP for everything else.

  • Seamless integration with Kubernetes. STUNner can be deployed into any Kubernetes cluster, even into restricted ones like GKE Autopilot, using a single command. Manage your HTTP/HTTPS application servers with your favorite service mesh, and STUNner takes care of all media streams, WebRTC, SIP or SRT. STUNner implements the Kubernetes Gateway API so you configure it in exactly the same way as the rest of your workload through easy-to-use YAML manifests.

  • Secure perimeter defense. No need to open thousands of UDP/TCP ports on your media servers; with STUNner all media is received through a single gateway port. Get rid of the Kubernetes security monstrosities like privileged pods and hostNetwork/hostPort services typically recommended as a prerequisite to containerizing a WebRTC media plane or a SIP gateway: with STUNner your media servers run in ordinary unprivileged Kubernetes pods behind a single gateway Service.

  • No reliance on external services for NAT traversal. Can't afford a hosted TURN service for client-side NAT traversal? STUNner runs in the same cluster as the rest of your WebRTC infrastructure, and any WebRTC client can connect to it directly without the use of any external STUN/TURN service whatsoever.

  • SIP trunks into the cluster (beta). Connect a carrier's SIP trunk to SIP servers running in ordinary pods and STUNner does the rest: it proxies SIP signaling traffic and relays RTP media into the cluster via a single external address. See the SIP gateway guide for details.

  • Live video streams into the cluster (beta). Point your encoders, drones and cameras at one public UDP port and STUNner routes every SRT stream by its stream ID: the publisher and the readers of a stream reach the same media server pod, and new streams land on new pods as you scale out. See the SRT gateway guide for details.

  • Scale your media infrastructure. Tired of manually provisioning your media servers? STUNner lets you deploy the entire media infrastructure into ordinary Kubernetes pods, thus scaling the media plane is as easy as issuing a kubectl scale command. Better yet, you can use the built in Kubernetes autoscalers to automatically resize your workload based on demand.

  • Minimal client-side configuration. STUNner comes with a built-in authentication service that can be used to generate time-windowed per-user TURN credentials through a standards compliant HTTP REST API. Just set the generated ICE configuration in the PeerConnection JavaScript API and your clients will readily start using your Kubernetes-based WebRTC service via STUNner.

  • Carrier-grade performance. Written in pure Go using the battle-tested pion/webrtc framework, even STUNner's open-source tier is already extremely fast and scalable. But with STUNner's industry-leading Linux/eBPF kernel offload engine enabled (on every tier, up to the offload limit of the tier), you can get up to 10 Gbps TURN/UDP performance per CPU core(!) at microsecond-scale latency.

Getting Started

With a minimal understanding of WebRTC, SIP or SRT and Kubernetes, deploying STUNner should take less than 5 minutes.

Note that the default installation does not contain an application server, a media server or a SIP server: STUNner is not a media service in itself, it is merely an enabler for you to deploy your own media infrastructure into Kubernetes.

The simplest way to deploy STUNner is through Helm. STUNner configuration parameters are available for customization as Helm Values.

helm repo add stunner https://l7mp.io/stunner
helm repo update
helm install stunner stunner/stunner --create-namespace --namespace=stunner-system

Find out more about the charts in the STUNner-helm repository.

Usage

STUNner comes with a wide selection of tutorials and demos that teach you how to deploy all kinds of WebRTC and SIP services into Kubernetes. The first couple of tutorials present the basic concepts, especially the use of the Kubernetes Gateway API to configure STUNner and the tunnel mode of stunnerd to test it. Each subsequent demo showcases a specific WebRTC application, from desktop streaming and video-conferencing to cloud-gaming, and goes from a clean Kubernetes cluster to a working and usable publicly available WebRTC service in 5-10 minutes using a purely declarative configuration.

Documentation

The documentation of the stable release can be found here. The documentation for the latest development release can be found here.

Help

STUNner development is coordinated in Discord, feel free to join.

License

Copyright 2021-2026 by its authors. Some rights reserved. See AUTHORS.

MIT License - see LICENSE for full text.

Acknowledgments

Initial code adopted from pion/stun and pion/turn.

Documentation

Overview

Package stunner contains the public API for l7mp/stunner, a Kubernetes ingress gateway for WebRTC.

Index

Constants

View Source
const DefaultLogLevel = "all:WARN"

DefaultLogLevel indicates the default log level.

Variables

View Source
var DefaultInstanceId = fmt.Sprintf("default/stunnerd-%s", uuid.New().String())

DefaultInstanceId is the default instance id for stunnerd processes.

View Source
var LogBurst = 50

LogBurst is the default burst size of a rate-limited logger.

View Source
var LogRateLimit rate.Limit = 5.0

LogRateLimit is the default number of log events per second of a rate-limited logger, at every level: the loggers a client can make log per packet, see LogRateLimitedScopes.

View Source
var LogRateLimitedScopes = []string{"listener-", "cluster-", "server-", "turn"}

LogRateLimitedScopes are the prefixes of the rate-limited logger scopes: the listeners, the clusters, the servers and the TURN machinery, each scope with a token bucket of its own.

Functions

func GenerateSelfSignedKey

func GenerateSelfSignedKey() ([]byte, []byte, error)

GenerateSelfSignedKey is a rudimentary hack to generate self-signed certificates used to bootstrap the default config for TLS/DTLS listeners and for testing. Use for testing purposes only!

func NewDefaultConfig

func NewDefaultConfig(uri string) (*stnrv2.StunnerConfig, error)

NewDefaultConfig builds a default configuration from a TURN server URI. Example: the URI `turn://user:pass@127.0.0.1:3478?transport=udp` will be parsed into a STUNner configuration with a TURN server listening at UDP port 3478 on every address and advertising its relays at 127.0.0.1, with plain-text authentication using the username/password pair `user:pass`, relaying to every peer. Health-checking is enabled at the default endpoint, metric scraping is disabled.

Types

type LogOptions

type LogOptions = logger.Options

LogOptions configures logging behavior for STUNner.

type Options

type Options struct {
	// Name is the identifier of this stunnerd daemon instance. Defaults to hostname.
	Name string
	// DryRun suppresses sideeffects: STUNner will not initialize listener sockets and bring up
	// the TURN server, and it will not fire up the health-check and the metrics
	// servers. Intended for testing, default is false.
	DryRun bool
	// SuppressRollback controls whether to rollback to the last working configuration after a
	// failed reconciliation request. Default is false, which means to always do a rollback.
	SuppressRollback bool
	// LogOptions controls logger settings (level, optional rate limiter settings).
	LogOptions LogOptions
	// Resolver swaps the internal DNS resolver with a custom implementation. Intended for
	// testing.
	Resolver resolver.DnsResolver
	// NodeName is the name of the Kubernetes node the TURN server is running on (if any).
	NodeName string
	// Net will switch on testing mode, using a vnet.Net instance to run STUNner over an
	// emulated data-plane.
	Net transport.Net
	// BuildInfo is the version of the binary, reported in the admin status and the build info
	// metric.
	BuildInfo buildinfo.BuildInfo
}

Options defines various options for the STUNner server.

type Stunner

type Stunner struct {
	// contains filtered or unexported fields
}

Stunner is an instance of the STUNner daemon.

func NewStunner

func NewStunner(options Options) *Stunner

NewStunner creates a new STUNner daemon for the specified Options. Call Reconcile to reconcile the daemon for a new configuration. The daemon is "alive" once the main object is initialized, and "ready" after the first successful reconciliation.

func (*Stunner) AllocationCount

func (s *Stunner) AllocationCount() int

AllocationCount returns the number of live sessions (TURN allocations and L4 flows) summed over all servers.

func (*Stunner) Close

func (s *Stunner) Close()

Close stops the STUNner daemon, cleans up any internal state, and closes all connections.

func (*Stunner) GetActiveConnections

func (s *Stunner) GetActiveConnections() int64

GetActiveConnections returns the number of live sessions: TURN allocations and L4 flows.

func (*Stunner) GetAdmin

func (s *Stunner) GetAdmin() *object.Admin

GetAdmin returns the Admin Object, or nil if not registered.

func (*Stunner) GetAuth

func (s *Stunner) GetAuth(name string) *object.Auth

GetAuth returns the authentication policy of a name, or nil if there is none.

func (*Stunner) GetCluster

func (s *Stunner) GetCluster(name string) *object.Cluster

GetCluster returns a Cluster by name, or nil if not found.

func (*Stunner) GetConfig

func (s *Stunner) GetConfig() *stnrv2.StunnerConfig

GetConfig returns the configuration of the running STUNner daemon. The root Object assembles the StunnerConfig from its descendants, see internal/object/stunner.go.

func (*Stunner) GetId

func (s *Stunner) GetId() string

GetId returns the id of the current stunnerd instance.

func (*Stunner) GetListener

func (s *Stunner) GetListener(name string) *object.Listener

GetListener returns a Listener by name, or nil if not found.

func (*Stunner) GetListeners

func (s *Stunner) GetListeners() []*object.Listener

GetListeners returns every Listener in stable order.

func (*Stunner) GetLogger

func (s *Stunner) GetLogger() logging.LoggerFactory

GetLogger returns the logger factory of the running daemon.

func (*Stunner) GetServer

func (s *Stunner) GetServer(name string) runtime.Object

GetServer returns a Server by name, or nil if not found.

func (*Stunner) GetServers

func (s *Stunner) GetServers() []runtime.Object

GetServers returns every Server in stable order.

func (*Stunner) GetStatus

func (s *Stunner) GetStatus() stnrv2.Status

GetStatus returns the status of the daemon: the statuses of its objects, the number of live sessions and the readiness. It is the status the /status endpoint of the health check serves.

func (*Stunner) GetVersion

func (s *Stunner) GetVersion() string

GetVersion returns the STUNner API version.

func (*Stunner) IsReady

func (s *Stunner) IsReady() bool

IsReady returns true if the STUNner instance is ready to serve allocation requests.

func (*Stunner) LoadConfig

func (s *Stunner) LoadConfig(origin string) (*stnrv2.StunnerConfig, error)

LoadConfig loads a configuration from an origin, with the environment of this process substituted into it.

func (*Stunner) Reconcile

func (s *Stunner) Reconcile(req *stnrv2.StunnerConfig) error

Reconcile handles updates to the STUNner configuration. The actual walk is delegated to the reconciler engine; this method only manages the readiness bit.

Returns nil if nothing changed in a way that required a restart, stnrv2.ErrRestarted listing any objects that were bounced (safe to ignore), or a non-nil error if the config was rejected, in which case the previous configuration is rolled back unless SuppressRollback is set.

func (*Stunner) SetLogLevel

func (s *Stunner) SetLogLevel(levelSpec string)

SetLogLevel sets the loglevel.

func (*Stunner) Shutdown

func (s *Stunner) Shutdown()

Shutdown causes STUNner to fail the readiness check. Meanwhile, it will keep on serving connections. This function should be called after the main program catches a SIGTERM.

func (*Stunner) WatchConfig

func (s *Stunner) WatchConfig(ctx context.Context, origin string, ch chan<- *stnrv2.StunnerConfig, suppressDelete bool) error

WatchConfig watches a configuration from an origin, with the environment of this process substituted into every update.

Directories

Path Synopsis
cmd
icetester command
mediactl command
Command mediactl is a media source and sink for testing media gateways: it sends packets and measures what comes back, or answers and echoes, over SIP/RTP, UDP, TCP, TURN and SRT.
Command mediactl is a media source and sink for testing media gateways: it sends packets and measures what comes back, or answers and echoes, over SIP/RTP, UDP, TCP, TURN and SRT.
stunnerctl command
stunnerd command
internal
api
Package api holds the contracts between the dataplane objects, which refer to each other by name.
Package api holds the contracts between the dataplane objects, which refer to each other by name.
dialer
Package dialer implements the transport of a cluster: the conns, relay sockets and relayed listeners towards the peers, tagged and accounted under the cluster's name, and the socket of a dialing listener, which reaches its peer through a dialer of its own, accounted as the listener.
Package dialer implements the transport of a cluster: the conns, relay sockets and relayed listeners towards the peers, tagged and accounted under the cluster's name, and the socket of a dialing listener, which reaches its peer through a dialer of its own, accounted as the listener.
filter
Package filter implements the filters of stunnerd: named rules admitting or dropping traffic by address and port.
Package filter implements the filters of stunnerd: named rules admitting or dropping traffic by address and port.
netconn
Package netconn tags a conn with its listener or cluster and its wire.
Package netconn tags a conn with its listener or cluster and its wire.
netconn/account
Package account is the accounting layer of the conn stack: it counts the traffic of a transport in telemetry under the name of the listener or cluster the transport belongs to, and adds no getter of its own, so what comes out is the same contract that went in.
Package account is the accounting layer of the conn stack: it counts the traffic of a transport in telemetry under the name of the listener or cluster the transport belongs to, and adds no getter of its own, so what comes out is the same contract that went in.
object
Package object implements the STUNner dataplane objects (Admin, Auth, Filter, Cluster, Server, Listener, Health, Metrics, Offload) and the declarative object hierarchy (the catalog).
Package object implements the STUNner dataplane objects (Admin, Auth, Filter, Cluster, Server, Listener, Health, Metrics, Offload) and the declarative object hierarchy (the catalog).
offload
Package offload implements the kernel offload of relayed UDP flows.
Package offload implements the kernel offload of relayed UDP flows.
proto/fifo
Package fifo implements in-process named fifos: a listener makes a fifo under a name and a dialer opens it.
Package fifo implements in-process named fifos: a listener makes a fifo under a name and a dialer opens it.
proto/ng
Package ng implements rtpengine's ng control protocol, in bencode or JSON.
Package ng implements rtpengine's ng control protocol, in bencode or JSON.
proto/siptx
Package siptx runs SIP transactions over net.Conns, on sipgo's transactions.
Package siptx runs SIP transactions over net.Conns, on sipgo's transactions.
reconciler
Package reconciler implements the engine that converges the STUNner object tree to a desired StunnerConfig.
Package reconciler implements the engine that converges the STUNner object tree to a desired StunnerConfig.
router
Package router implements the destinations of a cluster: its endpoints, resolved.
Package router implements the destinations of a cluster: its endpoints, resolved.
runtime
Package runtime is the kernel of the STUNner object system: it defines the node contracts (Runnable, Reconcilable, Object), the Registry that stores every live node keyed by (type, name) with parent edges, and the Runtime, the single cross-object access point carrying process-wide dependencies, registry-backed config/status lookups, and the readiness/shutdown flags.
Package runtime is the kernel of the STUNner object system: it defines the node contracts (Runnable, Reconcilable, Object), the Registry that stores every live node keyed by (type, name) with parent edges, and the Runtime, the single cross-object access point carrying process-wide dependencies, registry-backed config/status lookups, and the readiness/shutdown flags.
server
Package server holds what the TURN and L4 servers (the subpackages) share: the accept queue, the conntrack and ErrNotServing.
Package server holds what the TURN and L4 servers (the subpackages) share: the accept queue, the conntrack and ErrNotServing.
server/balancer
Package balancer chooses the peers of a server among the targets of its clusters, by a load-balancing policy.
Package balancer chooses the peers of a server among the targets of its clusters, by a load-balancing policy.
server/l4
Package l4 implements the L4 server: every client conn becomes a flow to an endpoint of the server's clusters.
Package l4 implements the L4 server: every client conn becomes a flow to an endpoint of the server's clusters.
server/rtp
Package rtp implements the RTP server, a media proxy driven over ng.
Package rtp implements the RTP server, a media proxy driven over ng.
server/sip
Package sip implements the SIP server, a transaction-stateful proxy of inbound calls.
Package sip implements the SIP server, a transaction-stateful proxy of inbound calls.
server/srt
Package srt implements the SRT server: it routes every SRT flow by the stream it names to the endpoint holding the stream and relays it, the stream's encryption untouched.
Package srt implements the SRT server: it routes every SRT flow by the stream it names to the endpoint holding the stream and relays it, the stream's encryption untouched.
server/turn
Package turn implements the TURN server: one pion/turn instance serving the client conns handed to it, relaying through the server's clusters.
Package turn implements the TURN server: one pion/turn instance serving the client conns handed to it, relaying through the server's clusters.
pkg
apis/v1
Package v1 is the v1 version of the STUNner API.
Package v1 is the v1 version of the STUNner API.
apis/v2
Package v2 is the v2 version of the STUNner API.
Package v2 is the v2 version of the STUNner API.
authentication
Package authentication contains the routines a TURN server checks STUNner authentication credentials with; the credentials themselves are generated by the auth policies of the API.
Package authentication contains the routines a TURN server checks STUNner authentication credentials with; the credentials themselves are generated by the auth policies of the API.
config/client/api
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.
config/license
Package to handle the licensing status of a client.
Package to handle the licensing status of a client.
config/server/api
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.
icetester
Package icetester runs the ICE test of stunnerctl: it installs test Gateways and a WebRTC echo backend in a namespace of its own, then connects to the backend through every test Gateway, over TURN by WHIP, and streams packets to the echo.
Package icetester runs the ICE test of stunnerctl: it installs test Gateways and a WebRTC echo backend in a namespace of its own, then connects to the backend through every test Gateway, over TURN by WHIP, and streams packets to the echo.
mediactl
Package mediactl holds the media sources and sinks of the mediactl tool and the tests: packet streams that measure the bitrate, the loss and the round trip, and echo servers, over any net.Conn.
Package mediactl holds the media sources and sinks of the mediactl tool and the tests: packet streams that measure the bitrate, the loss and the round trip, and echo servers, over any net.Conn.
mediactl/k8s
Package k8s resolves the k8s:// addresses of mediactl and the stunnerd tunnel from a Kubernetes cluster, through the kubeconfig of the caller:
Package k8s resolves the k8s:// addresses of mediactl and the stunnerd tunnel from a Kubernetes cluster, through the kubeconfig of the caller:
mediactl/rtp
Package rtp frames a packet conn as an RTP session: a net.Conn whose writes leave as the payloads of RTP packets and whose reads return the payloads of the RTP packets received.
Package rtp frames a packet conn as an RTP session: a net.Conn whose writes leave as the payloads of RTP packets and whose reads return the payloads of the RTP packets received.
mediactl/sip
Package sip is a minimal SIP phone, a dialer and a listener of calls: Dial and DialContext return a call once it is answered, Accept the next call the phone answered.
Package sip is a minimal SIP phone, a dialer and a listener of calls: Dial and DialContext return a call once it is answered, Accept the next call the phone answered.
mediactl/srt
Package srt holds the SRT dialer and listener of mediactl: a dialer calls for a stream in a mode, named in the access control syntax of the stream ID, a listener takes the callers of a passphrase, passes every published stream to the readers of the same stream itself and returns the other callers, for mediactl.Serve to echo.
Package srt holds the SRT dialer and listener of mediactl: a dialer calls for a stream in a mode, named in the access control syntax of the stream ID, a listener takes the callers of a passphrase, passes every published stream to the readers of the same stream itself and returns the other callers, for mediactl.Serve to echo.
mediactl/turn
Package turn holds the TURN dialer of mediactl: conns to peers relayed through a TURN server, over a UDP allocation or an RFC 6062 TCP connection.
Package turn holds the TURN dialer of mediactl: conns to peers relayed through a TURN server, over a UDP allocation or an RFC 6062 TCP connection.
udp
Package udp implements UDP listeners as net.Listeners: every client, identified by its address, gets a conn of its own.
Package udp implements UDP listeners as net.Listeners: every client, identified by its address, gets a conn of its own.
utils/discovery
Package discovery finds STUNner's components in a Kubernetes cluster, the config discovery server of the gateway operator, the stunnerd pods of a Gateway and the auth service, and opens port-forwards to them.
Package discovery finds STUNner's components in a Kubernetes cluster, the config discovery server of the gateway operator, the stunnerd pods of a Gateway and the auth service, and opens port-forwards to them.
utils/turnclient
Package turnclient opens client sessions on a TURN server over any of the TURN transports (TURN-UDP, TURN-TCP, TURN-TLS, TURN-DTLS).
Package turnclient opens client sessions on a TURN server over any of the TURN transports (TURN-UDP, TURN-TCP, TURN-TLS, TURN-DTLS).
whipconn
A simple WHIP client and server that implement a stream connection abstraction on top of a WebRTC data channel published via WHIP.
A simple WHIP client and server that implement a stream connection abstraction on top of a WebRTC data channel published via WHIP.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址