diff --git a/dev/runtime/config.yml b/dev/runtime/config.yml index ec2ca1c7..c08f1621 100644 --- a/dev/runtime/config.yml +++ b/dev/runtime/config.yml @@ -120,6 +120,10 @@ session: webrtc: icelite: true iceservers: - - urls: [ stun:stun.l.google.com:19302 ] - # username: foo - # credential: bar + # Backend servers are ignored if icelite is true. + backend: + - urls: [ stun:stun.l.google.com:19302 ] + frontend: + - urls: [ stun:stun.l.google.com:19305 ] + #username: foo + #credential: bar diff --git a/internal/config/webrtc.go b/internal/config/webrtc.go index 2af7fa35..54a40b5b 100644 --- a/internal/config/webrtc.go +++ b/internal/config/webrtc.go @@ -16,13 +16,14 @@ import ( const defStunSrv = "stun:stun.l.google.com:19302" type WebRTC struct { - ICELite bool - ICETrickle bool - ICEServers []types.ICEServer - EphemeralMin uint16 - EphemeralMax uint16 - TCPMux int - UDPMux int + ICELite bool + ICETrickle bool + ICEServersFrontend []types.ICEServer + ICEServersBackend []types.ICEServer + EphemeralMin uint16 + EphemeralMax uint16 + TCPMux int + UDPMux int NAT1To1IPs []string IpRetrievalUrl string @@ -43,11 +44,21 @@ func (WebRTC) Init(cmd *cobra.Command) error { return err } - cmd.PersistentFlags().String("webrtc.iceservers", "[]", "STUN and TURN servers in JSON format with `urls`, `username`, `password` keys") + cmd.PersistentFlags().String("webrtc.iceservers", "[]", "Global STUN and TURN servers in JSON format with `urls`, `username` and `credential` keys") if err := viper.BindPFlag("webrtc.iceservers", cmd.PersistentFlags().Lookup("webrtc.iceservers")); err != nil { return err } + cmd.PersistentFlags().String("webrtc.iceservers.frontend", "[]", "Frontend only STUN and TURN servers in JSON format with `urls`, `username` and `credential` keys") + if err := viper.BindPFlag("webrtc.iceservers.frontend", cmd.PersistentFlags().Lookup("webrtc.iceservers.frontend")); err != nil { + return err + } + + cmd.PersistentFlags().String("webrtc.iceservers.backend", "[]", "Backend only STUN and TURN servers in JSON format with `urls`, `username` and `credential` keys") + if err := viper.BindPFlag("webrtc.iceservers.backend", cmd.PersistentFlags().Lookup("webrtc.iceservers.backend")); err != nil { + return err + } + cmd.PersistentFlags().String("webrtc.epr", "", "limits the pool of ephemeral ports that ICE UDP connections can allocate from") if err := viper.BindPFlag("webrtc.epr", cmd.PersistentFlags().Lookup("webrtc.epr")); err != nil { return err @@ -97,16 +108,43 @@ func (s *WebRTC) Set() { s.ICELite = viper.GetBool("webrtc.icelite") s.ICETrickle = viper.GetBool("webrtc.icetrickle") - if err := viper.UnmarshalKey("webrtc.iceservers", &s.ICEServers, viper.DecodeHook( - utils.JsonStringAutoDecode(s.ICEServers), + // parse frontend ice servers + if err := viper.UnmarshalKey("webrtc.iceservers.frontend", &s.ICEServersFrontend, viper.DecodeHook( + utils.JsonStringAutoDecode([]types.ICEServer{}), )); err != nil { - log.Warn().Err(err).Msgf("unable to parse ICE servers") + log.Warn().Err(err).Msgf("unable to parse frontend ICE servers") } - if len(s.ICEServers) == 0 { - s.ICEServers = append(s.ICEServers, types.ICEServer{ - URLs: []string{defStunSrv}, - }) + // parse backend ice servers + if err := viper.UnmarshalKey("webrtc.iceservers.backend", &s.ICEServersBackend, viper.DecodeHook( + utils.JsonStringAutoDecode([]types.ICEServer{}), + )); err != nil { + log.Warn().Err(err).Msgf("unable to parse backend ICE servers") + } + + if s.ICELite && len(s.ICEServersBackend) > 0 { + log.Warn().Msgf("ICE Lite is enabled, but backend ICE servers are configured. Backend ICE servers will be ignored.") + } + + // if no frontend or backend ice servers are configured + if len(s.ICEServersFrontend) == 0 && len(s.ICEServersBackend) == 0 { + // parse global ice servers + var iceServers []types.ICEServer + if err := viper.UnmarshalKey("webrtc.iceservers", &iceServers, viper.DecodeHook( + utils.JsonStringAutoDecode([]types.ICEServer{}), + )); err != nil { + log.Warn().Err(err).Msgf("unable to parse global ICE servers") + } + + // add default stun server if none are configured + if len(iceServers) == 0 { + iceServers = append(iceServers, types.ICEServer{ + URLs: []string{defStunSrv}, + }) + } + + s.ICEServersFrontend = append(s.ICEServersFrontend, iceServers...) + s.ICEServersBackend = append(s.ICEServersBackend, iceServers...) } s.TCPMux = viper.GetInt("webrtc.tcpmux") diff --git a/internal/webrtc/manager.go b/internal/webrtc/manager.go index 1b483e31..d0782de4 100644 --- a/internal/webrtc/manager.go +++ b/internal/webrtc/manager.go @@ -47,7 +47,7 @@ func New(desktop types.DesktopManager, capture types.CaptureManager, config *con if !config.ICELite { ICEServers := []webrtc.ICEServer{} - for _, server := range config.ICEServers { + for _, server := range config.ICEServersBackend { var credential any if server.Credential != "" { credential = server.Credential @@ -137,7 +137,8 @@ func (manager *WebRTCManagerCtx) Start() { manager.logger.Info(). Bool("icelite", manager.config.ICELite). Bool("icetrickle", manager.config.ICETrickle). - Interface("iceservers", manager.config.ICEServers). + Interface("iceservers-frontend", manager.config.ICEServersFrontend). + Interface("iceservers-backend", manager.config.ICEServersBackend). Str("nat1to1", strings.Join(manager.config.NAT1To1IPs, ",")). Str("epr", fmt.Sprintf("%d-%d", manager.config.EphemeralMin, manager.config.EphemeralMax)). Int("tcpmux", manager.config.TCPMux). @@ -155,7 +156,7 @@ func (manager *WebRTCManagerCtx) Shutdown() error { } func (manager *WebRTCManagerCtx) ICEServers() []types.ICEServer { - return manager.config.ICEServers + return manager.config.ICEServersFrontend } func (manager *WebRTCManagerCtx) newPeerConnection(bitrate int, codecs []codec.RTPCodec, logger zerolog.Logger) (*webrtc.PeerConnection, cc.BandwidthEstimator, error) {