(webrtc) added support for ice mux tcp and nat1to1ips (#1323)
* 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 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
@@ -147,6 +147,12 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
webrtcICEHostNAT1To1IPs:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
webrtcICETCPMuxAddress:
|
||||
type: string
|
||||
|
||||
# paths
|
||||
paths:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
+10
-8
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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")
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -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{
|
||||
@@ -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),
|
||||
@@ -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)
|
||||
}
|
||||
@@ -206,6 +233,8 @@ outer:
|
||||
&s.wg,
|
||||
s.pathManager,
|
||||
s,
|
||||
s.iceTCPMux,
|
||||
s.iceHostNAT1To1IPs,
|
||||
)
|
||||
s.conns[c] = struct{}{}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user