Browse Source

(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>
pull/1364/head
andrew-ld 4 years ago committed by GitHub
parent
commit
b27c363ecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      apidocs/openapi.yaml
  2. 4
      go.mod
  3. 2
      internal/conf/conf.go
  4. 6
      internal/core/core.go
  5. 49
      internal/core/webrtc_conn.go
  6. 34
      internal/core/webrtc_server.go
  7. 7
      rtsp-simple-server.yml

6
apidocs/openapi.yaml

@ -147,6 +147,12 @@ components:
type: array type: array
items: items:
type: string type: string
webrtcICEHostNAT1To1IPs:
type: array
items:
type: string
webrtcICETCPMuxAddress:
type: string
# paths # paths
paths: paths:

4
go.mod

@ -16,6 +16,8 @@ require (
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/notedit/rtmp v0.0.2 github.com/notedit/rtmp v0.0.2
github.com/orcaman/writerseeker v0.0.0 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/rtp v1.7.13
github.com/pion/webrtc/v3 v3.1.47 github.com/pion/webrtc/v3 v3.1.47
github.com/stretchr/testify v1.7.1 github.com/stretchr/testify v1.7.1
@ -42,8 +44,6 @@ require (
github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pion/datachannel v1.5.2 // indirect github.com/pion/datachannel v1.5.2 // indirect
github.com/pion/dtls/v2 v2.1.5 // 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/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect github.com/pion/mdns v0.0.5 // indirect
github.com/pion/randutil v0.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect

2
internal/conf/conf.go

@ -232,6 +232,8 @@ type Conf struct {
WebRTCAllowOrigin string `json:"webrtcAllowOrigin"` WebRTCAllowOrigin string `json:"webrtcAllowOrigin"`
WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"` WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"`
WebRTCICEServers []string `json:"webrtcICEServers"` WebRTCICEServers []string `json:"webrtcICEServers"`
WebRTCICEHostNAT1To1IPs []string `json:"webrtcICEHostNAT1To1IPs"`
WebRTCICETCPMuxAddress string `json:"webrtcICETCPMuxAddress"`
// paths // paths
Paths map[string]*PathConf `json:"paths"` Paths map[string]*PathConf `json:"paths"`

6
internal/core/core.go

@ -413,6 +413,8 @@ func (p *Core) createResources(initial bool) error {
p.pathManager, p.pathManager,
p.metrics, p.metrics,
p, p,
p.conf.WebRTCICEHostNAT1To1IPs,
p.conf.WebRTCICETCPMuxAddress,
) )
if err != nil { if err != nil {
return err return err
@ -574,7 +576,9 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
!reflect.DeepEqual(newConf.WebRTCICEServers, p.conf.WebRTCICEServers) || !reflect.DeepEqual(newConf.WebRTCICEServers, p.conf.WebRTCICEServers) ||
newConf.ReadBufferCount != p.conf.ReadBufferCount || newConf.ReadBufferCount != p.conf.ReadBufferCount ||
closeMetrics || closeMetrics ||
closePathManager closePathManager ||
!reflect.DeepEqual(newConf.WebRTCICEHostNAT1To1IPs, p.conf.WebRTCICEHostNAT1To1IPs) ||
newConf.WebRTCICETCPMuxAddress != p.conf.WebRTCICETCPMuxAddress
closeAPI := newConf == nil || closeAPI := newConf == nil ||
newConf.API != p.conf.API || newConf.API != p.conf.API ||

49
internal/core/webrtc_conn.go

@ -24,6 +24,8 @@ import (
"github.com/aler9/gortsplib/v2/pkg/ringbuffer" "github.com/aler9/gortsplib/v2/pkg/ringbuffer"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/pion/ice/v2"
"github.com/pion/interceptor"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/aler9/rtsp-simple-server/internal/conf" "github.com/aler9/rtsp-simple-server/internal/conf"
@ -34,6 +36,31 @@ const (
handshakeDeadline = 10 * time.Second 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 { type webRTCTrack struct {
media *media.Media media *media.Media
format format.Format format format.Format
@ -68,6 +95,8 @@ type webRTCConn struct {
wg *sync.WaitGroup wg *sync.WaitGroup
pathManager webRTCConnPathManager pathManager webRTCConnPathManager
parent webRTCConnParent parent webRTCConnParent
iceTCPMux ice.TCPMux
iceHostNAT1To1IPs []string
ctx context.Context ctx context.Context
ctxCancel func() ctxCancel func()
@ -86,6 +115,8 @@ func newWebRTCConn(
wg *sync.WaitGroup, wg *sync.WaitGroup,
pathManager webRTCConnPathManager, pathManager webRTCConnPathManager,
parent webRTCConnParent, parent webRTCConnParent,
iceTCPMux ice.TCPMux,
iceHostNAT1To1IPs []string,
) *webRTCConn { ) *webRTCConn {
ctx, ctxCancel := context.WithCancel(parentCtx) ctx, ctxCancel := context.WithCancel(parentCtx)
@ -101,6 +132,8 @@ func newWebRTCConn(
ctxCancel: ctxCancel, ctxCancel: ctxCancel,
uuid: uuid.New(), uuid: uuid.New(),
created: time.Now(), created: time.Now(),
iceTCPMux: iceTCPMux,
iceHostNAT1To1IPs: iceHostNAT1To1IPs,
} }
c.log(logger.Info, "opened") c.log(logger.Info, "opened")
@ -222,9 +255,19 @@ func (c *webRTCConn) runInner(ctx context.Context) error {
return err return err
} }
pc, err := webrtc.NewPeerConnection(webrtc.Configuration{ configuration := webrtc.Configuration{ICEServers: c.genICEServers()}
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 { if err != nil {
return err return err
} }

34
internal/core/webrtc_server.go

@ -15,6 +15,8 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "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/conf"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
@ -81,9 +83,13 @@ type webRTCServer struct {
ctxCancel func() ctxCancel func()
wg sync.WaitGroup wg sync.WaitGroup
ln net.Listener ln net.Listener
tcpMuxLn net.Listener
tlsConfig *tls.Config tlsConfig *tls.Config
conns map[*webRTCConn]struct{} conns map[*webRTCConn]struct{}
iceTCPMux ice.TCPMux
iceHostNAT1To1IPs []string
// in // in
connNew chan webRTCConnNewReq connNew chan webRTCConnNewReq
chConnClose chan *webRTCConn chConnClose chan *webRTCConn
@ -105,6 +111,8 @@ func newWebRTCServer(
pathManager *pathManager, pathManager *pathManager,
metrics *metrics, metrics *metrics,
parent webRTCServerParent, parent webRTCServerParent,
iceHostNAT1To1IPs []string,
iceTCPMuxAddress string,
) (*webRTCServer, error) { ) (*webRTCServer, error) {
ln, err := net.Listen("tcp", address) ln, err := net.Listen("tcp", address)
if err != nil { 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) ctx, ctxCancel := context.WithCancel(parentCtx)
s := &webRTCServer{ s := &webRTCServer{
@ -138,7 +158,10 @@ func newWebRTCServer(
ctx: ctx, ctx: ctx,
ctxCancel: ctxCancel, ctxCancel: ctxCancel,
ln: ln, ln: ln,
tcpMuxLn: tcpMuxLn,
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
iceTCPMux: iceTCPMux,
iceHostNAT1To1IPs: iceHostNAT1To1IPs,
conns: make(map[*webRTCConn]struct{}), conns: make(map[*webRTCConn]struct{}),
connNew: make(chan webRTCConnNewReq), connNew: make(chan webRTCConnNewReq),
chConnClose: make(chan *webRTCConn), chConnClose: make(chan *webRTCConn),
@ -148,6 +171,10 @@ func newWebRTCServer(
s.log(logger.Info, "listener opened on "+address) 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 { if s.metrics != nil {
s.metrics.webRTCServerSet(s) s.metrics.webRTCServerSet(s)
} }
@ -206,6 +233,8 @@ outer:
&s.wg, &s.wg,
s.pathManager, s.pathManager,
s, s,
s.iceTCPMux,
s.iceHostNAT1To1IPs,
) )
s.conns[c] = struct{}{} s.conns[c] = struct{}{}
@ -253,6 +282,11 @@ outer:
s.ctxCancel() s.ctxCancel()
hs.Shutdown(context.Background()) hs.Shutdown(context.Background())
if s.tcpMuxLn != nil {
s.tcpMuxLn.Close()
}
s.ln.Close() // in case Shutdown() is called before Serve() s.ln.Close() // in case Shutdown() is called before Serve()
} }

7
rtsp-simple-server.yml

@ -196,6 +196,13 @@ webrtcTrustedProxies: []
# if user is "AUTH_SECRET", then authentication is secret based. # if user is "AUTH_SECRET", then authentication is secret based.
# the secret must be inserted into the pass field. # the secret must be inserted into the pass field.
webrtcICEServers: [stun:stun.l.google.com:19302] 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 # Path parameters

Loading…
Cancel
Save