single port ice using tcp and udp mux (#106)
This commit is contained in:
parent
a213ae400a
commit
c97b1fc454
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
- Automatic WebRTC SDP negotiation using onnegotiationneeded handlers. This allows adding/removing track on demand in a session.
|
- Automatic WebRTC SDP negotiation using onnegotiationneeded handlers. This allows adding/removing track on demand in a session.
|
||||||
|
- Added UDP and TCP mux for WebRTC connection. It should handle multiple peers.
|
||||||
|
|
||||||
## [n.eko v2.5](https://github.com/m1k1o/neko/releases/tag/v2.5)
|
## [n.eko v2.5](https://github.com/m1k1o/neko/releases/tag/v2.5)
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ type WebRTC struct {
|
|||||||
EphemeralMin uint16
|
EphemeralMin uint16
|
||||||
EphemeralMax uint16
|
EphemeralMax uint16
|
||||||
NAT1To1IPs []string
|
NAT1To1IPs []string
|
||||||
|
TCPMUX int
|
||||||
|
UDPMUX int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (WebRTC) Init(cmd *cobra.Command) error {
|
func (WebRTC) Init(cmd *cobra.Command) error {
|
||||||
@ -33,6 +35,16 @@ func (WebRTC) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("tcpmux", 0, "single TCP mux port for all peers")
|
||||||
|
if err := viper.BindPFlag("tcpmux", cmd.PersistentFlags().Lookup("tcpmux")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("udpmux", 0, "single UDP mux port for all peers")
|
||||||
|
if err := viper.BindPFlag("udpmux", cmd.PersistentFlags().Lookup("udpmux")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().String("ipfetch", "http://checkip.amazonaws.com", "automatically fetch IP address from given URL when nat1to1 is not present")
|
cmd.PersistentFlags().String("ipfetch", "http://checkip.amazonaws.com", "automatically fetch IP address from given URL when nat1to1 is not present")
|
||||||
if err := viper.BindPFlag("ipfetch", cmd.PersistentFlags().Lookup("ipfetch")); err != nil {
|
if err := viper.BindPFlag("ipfetch", cmd.PersistentFlags().Lookup("ipfetch")); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -58,6 +70,8 @@ func (WebRTC) Init(cmd *cobra.Command) error {
|
|||||||
|
|
||||||
func (s *WebRTC) Set() {
|
func (s *WebRTC) Set() {
|
||||||
s.NAT1To1IPs = viper.GetStringSlice("nat1to1")
|
s.NAT1To1IPs = viper.GetStringSlice("nat1to1")
|
||||||
|
s.TCPMUX = viper.GetInt("tcpmux")
|
||||||
|
s.UDPMUX = viper.GetInt("udpmux")
|
||||||
s.ICELite = viper.GetBool("icelite")
|
s.ICELite = viper.GetBool("icelite")
|
||||||
s.ICEServers = []webrtc.ICEServer{}
|
s.ICEServers = []webrtc.ICEServer{}
|
||||||
|
|
||||||
|
@ -7,14 +7,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
id string
|
id string
|
||||||
api *webrtc.API
|
mu sync.Mutex
|
||||||
engine *webrtc.MediaEngine
|
manager *WebRTCManager
|
||||||
manager *WebRTCManager
|
connection *webrtc.PeerConnection
|
||||||
settings *webrtc.SettingEngine
|
|
||||||
connection *webrtc.PeerConnection
|
|
||||||
configuration *webrtc.Configuration
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (peer *Peer) CreateOffer() (string, error) {
|
func (peer *Peer) CreateOffer() (string, error) {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ type WebRTCManager struct {
|
|||||||
sessions types.SessionManager
|
sessions types.SessionManager
|
||||||
remote types.RemoteManager
|
remote types.RemoteManager
|
||||||
config *config.WebRTC
|
config *config.WebRTC
|
||||||
|
api *webrtc.API
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *WebRTCManager) Start() {
|
func (manager *WebRTCManager) Start() {
|
||||||
@ -61,6 +63,10 @@ func (manager *WebRTCManager) Start() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err := manager.initAPI(); err != nil {
|
||||||
|
manager.logger.Panic().Err(err).Msg("failed to initialize webrtc API")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logger.Info().
|
manager.logger.Info().
|
||||||
Str("ice_lite", fmt.Sprintf("%t", manager.config.ICELite)).
|
Str("ice_lite", fmt.Sprintf("%t", manager.config.ICELite)).
|
||||||
Str("ice_servers", fmt.Sprintf("%+v", manager.config.ICEServers)).
|
Str("ice_servers", fmt.Sprintf("%+v", manager.config.ICEServers)).
|
||||||
@ -74,46 +80,96 @@ func (manager *WebRTCManager) Shutdown() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (types.Peer, error) {
|
func (manager *WebRTCManager) initAPI() error {
|
||||||
configuration := &webrtc.Configuration{
|
logger := loggerFactory{
|
||||||
ICEServers: manager.config.ICEServers,
|
logger: manager.logger,
|
||||||
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := webrtc.SettingEngine{
|
settings := webrtc.SettingEngine{
|
||||||
LoggerFactory: loggerFactory{
|
LoggerFactory: logger,
|
||||||
logger: manager.logger,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if manager.config.ICELite {
|
|
||||||
configuration = &webrtc.Configuration{
|
|
||||||
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
|
|
||||||
}
|
|
||||||
settings.SetLite(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
|
_ = settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
|
||||||
settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost)
|
settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost)
|
||||||
settings.SetICETimeouts(6*time.Second, 6*time.Second, 3*time.Second)
|
settings.SetICETimeouts(6*time.Second, 6*time.Second, 3*time.Second)
|
||||||
settings.SetSRTPReplayProtectionWindow(512)
|
settings.SetSRTPReplayProtectionWindow(512)
|
||||||
|
settings.SetLite(manager.config.ICELite)
|
||||||
|
|
||||||
// Create MediaEngine based off sdp
|
var networkType []webrtc.NetworkType
|
||||||
|
|
||||||
|
// Add TCP Mux
|
||||||
|
if manager.config.TCPMUX > 0 {
|
||||||
|
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||||
|
IP: net.IP{0, 0, 0, 0},
|
||||||
|
Port: manager.config.TCPMUX,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpMux := webrtc.NewICETCPMux(logger.NewLogger("ice-tcp"), tcpListener, 32)
|
||||||
|
settings.SetICETCPMux(tcpMux)
|
||||||
|
|
||||||
|
networkType = append(networkType, webrtc.NetworkTypeTCP4)
|
||||||
|
manager.logger.Info().Str("listener", tcpListener.Addr().String()).Msg("using TCP MUX")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add UDP Mux
|
||||||
|
if manager.config.UDPMUX > 0 {
|
||||||
|
udpListener, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
IP: net.IP{0, 0, 0, 0},
|
||||||
|
Port: manager.config.UDPMUX,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
udpMux := webrtc.NewICEUDPMux(logger.NewLogger("ice-udp"), udpListener)
|
||||||
|
settings.SetICEUDPMux(udpMux)
|
||||||
|
|
||||||
|
networkType = append(networkType, webrtc.NetworkTypeUDP4)
|
||||||
|
manager.logger.Info().Str("listener", udpListener.LocalAddr().String()).Msg("using UDP MUX")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable support for TCP and UDP ICE candidates
|
||||||
|
if len(networkType) > 0 {
|
||||||
|
settings.SetNetworkTypes(networkType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MediaEngine with selected codecs
|
||||||
engine := webrtc.MediaEngine{}
|
engine := webrtc.MediaEngine{}
|
||||||
|
|
||||||
_ = engine.RegisterCodec(manager.audioCodec, webrtc.RTPCodecTypeAudio)
|
_ = engine.RegisterCodec(manager.audioCodec, webrtc.RTPCodecTypeAudio)
|
||||||
_ = engine.RegisterCodec(manager.videoCodec, webrtc.RTPCodecTypeVideo)
|
_ = engine.RegisterCodec(manager.videoCodec, webrtc.RTPCodecTypeVideo)
|
||||||
|
|
||||||
|
// Register Interceptors
|
||||||
i := &interceptor.Registry{}
|
i := &interceptor.Registry{}
|
||||||
if err := webrtc.RegisterDefaultInterceptors(&engine, i); err != nil {
|
if err := webrtc.RegisterDefaultInterceptors(&engine, i); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create API with MediaEngine and SettingEngine
|
// Create API with MediaEngine and SettingEngine
|
||||||
api := webrtc.NewAPI(webrtc.WithMediaEngine(&engine), webrtc.WithSettingEngine(settings), webrtc.WithInterceptorRegistry(i))
|
manager.api = webrtc.NewAPI(
|
||||||
|
webrtc.WithMediaEngine(&engine),
|
||||||
|
webrtc.WithSettingEngine(settings),
|
||||||
|
webrtc.WithInterceptorRegistry(i),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (types.Peer, error) {
|
||||||
|
configuration := webrtc.Configuration{
|
||||||
|
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !manager.config.ICELite {
|
||||||
|
configuration.ICEServers = manager.config.ICEServers
|
||||||
|
}
|
||||||
|
|
||||||
// Create new peer connection
|
// Create new peer connection
|
||||||
connection, err := api.NewPeerConnection(*configuration)
|
connection, err := manager.api.NewPeerConnection(configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -173,13 +229,9 @@ func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (type
|
|||||||
})
|
})
|
||||||
|
|
||||||
peer := &Peer{
|
peer := &Peer{
|
||||||
id: id,
|
id: id,
|
||||||
api: api,
|
manager: manager,
|
||||||
engine: &engine,
|
connection: connection,
|
||||||
manager: manager,
|
|
||||||
settings: &settings,
|
|
||||||
connection: connection,
|
|
||||||
configuration: configuration,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.OnNegotiationNeeded(func() {
|
connection.OnNegotiationNeeded(func() {
|
||||||
|
Reference in New Issue
Block a user