Skip to content

Commit

Permalink
(webrtc) added support for ice mux tcp and nat1to1ips (#1323)
Browse files Browse the repository at this point in the history
* add webrtcp static tcp mux port

* add ice nat1 host configuration and cleanup

* typo

* rename config keys

* apply codecov suggestions

* apply review suggestions

* typo

* dont use deepequal for WebRTCICETCPMuxAddress

* unexport NewPeerConnection()

* remove Dockerfile

* use an empty list instead of nil value in webrtcICEHostNAT1To1IPs

* drop webrtcICETCPMuxEnable and enable TCP mux when webrtcICETCPMuxAddress is filled

* run go mod tidy

Co-authored-by: aler9 <[email protected]>
  • Loading branch information
andrew-ld and aler9 authored Dec 30, 2022
1 parent d15bde3 commit b27c363
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 32 deletions.
6 changes: 6 additions & 0 deletions apidocs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ components:
type: array
items:
type: string
webrtcICEHostNAT1To1IPs:
type: array
items:
type: string
webrtcICETCPMuxAddress:
type: string

# paths
paths:
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ require (
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/notedit/rtmp v0.0.2
github.com/orcaman/writerseeker v0.0.0
github.com/pion/ice/v2 v2.2.11
github.com/pion/interceptor v0.1.11
github.com/pion/rtp v1.7.13
github.com/pion/webrtc/v3 v3.1.47
github.com/stretchr/testify v1.7.1
Expand All @@ -42,8 +44,6 @@ require (
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pion/datachannel v1.5.2 // indirect
github.com/pion/dtls/v2 v2.1.5 // indirect
github.com/pion/ice/v2 v2.2.11 // indirect
github.com/pion/interceptor v0.1.11 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect
github.com/pion/randutil v0.1.0 // indirect
Expand Down
18 changes: 10 additions & 8 deletions internal/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,16 @@ type Conf struct {
HLSTrustedProxies IPsOrCIDRs `json:"hlsTrustedProxies"`

// WebRTC
WebRTCDisable bool `json:"webrtcDisable"`
WebRTCAddress string `json:"webrtcAddress"`
WebRTCEncryption bool `json:"webrtcEncryption"`
WebRTCServerKey string `json:"webrtcServerKey"`
WebRTCServerCert string `json:"webrtcServerCert"`
WebRTCAllowOrigin string `json:"webrtcAllowOrigin"`
WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"`
WebRTCICEServers []string `json:"webrtcICEServers"`
WebRTCDisable bool `json:"webrtcDisable"`
WebRTCAddress string `json:"webrtcAddress"`
WebRTCEncryption bool `json:"webrtcEncryption"`
WebRTCServerKey string `json:"webrtcServerKey"`
WebRTCServerCert string `json:"webrtcServerCert"`
WebRTCAllowOrigin string `json:"webrtcAllowOrigin"`
WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"`
WebRTCICEServers []string `json:"webrtcICEServers"`
WebRTCICEHostNAT1To1IPs []string `json:"webrtcICEHostNAT1To1IPs"`
WebRTCICETCPMuxAddress string `json:"webrtcICETCPMuxAddress"`

// paths
Paths map[string]*PathConf `json:"paths"`
Expand Down
6 changes: 5 additions & 1 deletion internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ func (p *Core) createResources(initial bool) error {
p.pathManager,
p.metrics,
p,
p.conf.WebRTCICEHostNAT1To1IPs,
p.conf.WebRTCICETCPMuxAddress,
)
if err != nil {
return err
Expand Down Expand Up @@ -574,7 +576,9 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
!reflect.DeepEqual(newConf.WebRTCICEServers, p.conf.WebRTCICEServers) ||
newConf.ReadBufferCount != p.conf.ReadBufferCount ||
closeMetrics ||
closePathManager
closePathManager ||
!reflect.DeepEqual(newConf.WebRTCICEHostNAT1To1IPs, p.conf.WebRTCICEHostNAT1To1IPs) ||
newConf.WebRTCICETCPMuxAddress != p.conf.WebRTCICETCPMuxAddress

closeAPI := newConf == nil ||
newConf.API != p.conf.API ||
Expand Down
85 changes: 64 additions & 21 deletions internal/core/webrtc_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"github.com/aler9/gortsplib/v2/pkg/ringbuffer"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"github.com/pion/ice/v2"
"github.com/pion/interceptor"
"github.com/pion/webrtc/v3"

"github.com/aler9/rtsp-simple-server/internal/conf"
Expand All @@ -34,6 +36,31 @@ const (
handshakeDeadline = 10 * time.Second
)

// newPeerConnection creates a PeerConnection with the default codecs and
// interceptors. See RegisterDefaultCodecs and RegisterDefaultInterceptors.
//
// This function is a copy of webrtc/peerconnection.go
// unlike the original one, allows you to add additional custom options
func newPeerConnection(configuration webrtc.Configuration,
options ...func(*webrtc.API),
) (*webrtc.PeerConnection, error) {
m := &webrtc.MediaEngine{}
if err := m.RegisterDefaultCodecs(); err != nil {
return nil, err
}

i := &interceptor.Registry{}
if err := webrtc.RegisterDefaultInterceptors(m, i); err != nil {
return nil, err
}

options = append(options, webrtc.WithMediaEngine(m))
options = append(options, webrtc.WithInterceptorRegistry(i))

api := webrtc.NewAPI(options...)
return api.NewPeerConnection(configuration)
}

type webRTCTrack struct {
media *media.Media
format format.Format
Expand Down Expand Up @@ -61,13 +88,15 @@ type webRTCConnParent interface {
}

type webRTCConn struct {
readBufferCount int
pathName string
wsconn *websocket.Conn
iceServers []string
wg *sync.WaitGroup
pathManager webRTCConnPathManager
parent webRTCConnParent
readBufferCount int
pathName string
wsconn *websocket.Conn
iceServers []string
wg *sync.WaitGroup
pathManager webRTCConnPathManager
parent webRTCConnParent
iceTCPMux ice.TCPMux
iceHostNAT1To1IPs []string

ctx context.Context
ctxCancel func()
Expand All @@ -86,21 +115,25 @@ func newWebRTCConn(
wg *sync.WaitGroup,
pathManager webRTCConnPathManager,
parent webRTCConnParent,
iceTCPMux ice.TCPMux,
iceHostNAT1To1IPs []string,
) *webRTCConn {
ctx, ctxCancel := context.WithCancel(parentCtx)

c := &webRTCConn{
readBufferCount: readBufferCount,
pathName: pathName,
wsconn: wsconn,
iceServers: iceServers,
wg: wg,
pathManager: pathManager,
parent: parent,
ctx: ctx,
ctxCancel: ctxCancel,
uuid: uuid.New(),
created: time.Now(),
readBufferCount: readBufferCount,
pathName: pathName,
wsconn: wsconn,
iceServers: iceServers,
wg: wg,
pathManager: pathManager,
parent: parent,
ctx: ctx,
ctxCancel: ctxCancel,
uuid: uuid.New(),
created: time.Now(),
iceTCPMux: iceTCPMux,
iceHostNAT1To1IPs: iceHostNAT1To1IPs,
}

c.log(logger.Info, "opened")
Expand Down Expand Up @@ -222,9 +255,19 @@ func (c *webRTCConn) runInner(ctx context.Context) error {
return err
}

pc, err := webrtc.NewPeerConnection(webrtc.Configuration{
ICEServers: c.genICEServers(),
})
configuration := webrtc.Configuration{ICEServers: c.genICEServers()}
settingsEngine := webrtc.SettingEngine{}

if c.iceTCPMux != nil {
settingsEngine.SetICETCPMux(c.iceTCPMux)
settingsEngine.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4})
}

if len(c.iceHostNAT1To1IPs) != 0 {
settingsEngine.SetNAT1To1IPs(c.iceHostNAT1To1IPs, webrtc.ICECandidateTypeHost)
}

pc, err := newPeerConnection(configuration, webrtc.WithSettingEngine(settingsEngine))
if err != nil {
return err
}
Expand Down
34 changes: 34 additions & 0 deletions internal/core/webrtc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (

"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/pion/ice/v2"
"github.com/pion/webrtc/v3"

"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger"
Expand Down Expand Up @@ -81,9 +83,13 @@ type webRTCServer struct {
ctxCancel func()
wg sync.WaitGroup
ln net.Listener
tcpMuxLn net.Listener
tlsConfig *tls.Config
conns map[*webRTCConn]struct{}

iceTCPMux ice.TCPMux
iceHostNAT1To1IPs []string

// in
connNew chan webRTCConnNewReq
chConnClose chan *webRTCConn
Expand All @@ -105,6 +111,8 @@ func newWebRTCServer(
pathManager *pathManager,
metrics *metrics,
parent webRTCServerParent,
iceHostNAT1To1IPs []string,
iceTCPMuxAddress string,
) (*webRTCServer, error) {
ln, err := net.Listen("tcp", address)
if err != nil {
Expand All @@ -124,6 +132,18 @@ func newWebRTCServer(
}
}

var iceTCPMux ice.TCPMux
var tcpMuxLn net.Listener
if iceTCPMuxAddress != "" {
tcpMuxLn, err = net.Listen("tcp", iceTCPMuxAddress)
if err != nil {
tcpMuxLn.Close()
return nil, err
}

iceTCPMux = webrtc.NewICETCPMux(nil, tcpMuxLn, 8)
}

ctx, ctxCancel := context.WithCancel(parentCtx)

s := &webRTCServer{
Expand All @@ -138,7 +158,10 @@ func newWebRTCServer(
ctx: ctx,
ctxCancel: ctxCancel,
ln: ln,
tcpMuxLn: tcpMuxLn,
tlsConfig: tlsConfig,
iceTCPMux: iceTCPMux,
iceHostNAT1To1IPs: iceHostNAT1To1IPs,
conns: make(map[*webRTCConn]struct{}),
connNew: make(chan webRTCConnNewReq),
chConnClose: make(chan *webRTCConn),
Expand All @@ -148,6 +171,10 @@ func newWebRTCServer(

s.log(logger.Info, "listener opened on "+address)

if tcpMuxLn != nil {
s.log(logger.Info, "ice mux tcp listener opened on "+iceTCPMuxAddress)
}

if s.metrics != nil {
s.metrics.webRTCServerSet(s)
}
Expand Down Expand Up @@ -206,6 +233,8 @@ outer:
&s.wg,
s.pathManager,
s,
s.iceTCPMux,
s.iceHostNAT1To1IPs,
)
s.conns[c] = struct{}{}

Expand Down Expand Up @@ -253,6 +282,11 @@ outer:
s.ctxCancel()

hs.Shutdown(context.Background())

if s.tcpMuxLn != nil {
s.tcpMuxLn.Close()
}

s.ln.Close() // in case Shutdown() is called before Serve()
}

Expand Down
7 changes: 7 additions & 0 deletions rtsp-simple-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ webrtcTrustedProxies: []
# if user is "AUTH_SECRET", then authentication is secret based.
# the secret must be inserted into the pass field.
webrtcICEServers: [stun:stun.l.google.com:19302]
# List of public IP addresses that are to be used as a host.
# This is used typically for servers that are behind 1:1 D-NAT.
webrtcICEHostNAT1To1IPs: []
# Address of a ICE TCP listener in format host:port.
# If filled, ICE traffic will come through a single TCP port,
# allowing the deployment of the server inside a container or behind a NAT.
webrtcICETCPMuxAddress:

###############################################
# Path parameters
Expand Down

0 comments on commit b27c363

Please sign in to comment.