Browse Source

Add option for ICE servers to be client only

pull/3164/head
Dan Bason 2 years ago
parent
commit
94efd0fa52
No known key found for this signature in database
GPG Key ID: 42721150F4584B4B
  1. 10
      README.md
  2. 7
      internal/conf/webrtc_ice_server.go
  3. 4
      internal/servers/webrtc/http_server.go
  4. 38
      internal/servers/webrtc/server.go
  5. 37
      internal/servers/webrtc/server_test.go
  6. 4
      internal/servers/webrtc/session.go

10
README.md

@ -1879,6 +1879,16 @@ webrtcICEServers2: @@ -1879,6 +1879,16 @@ webrtcICEServers2:
where secret is the secret of the TURN server. MediaMTX will generate a set of credentials by using the secret, and credentials will be sent to clients before the WebRTC/ICE connection is established.
In some cases you may want the browser to connect using TURN servers but have mediamtx not using TURN (for example if the TURN server is on the same network as mediamtx). To allow this you can configure the TURN server to be client only:
```yml
webrtcICEServers2:
- url: turn:host:port
username: user
password: password
clientOnly: true
```
### RTSP-specific features
#### Transport protocols

7
internal/conf/webrtc_ice_server.go

@ -2,7 +2,8 @@ package conf @@ -2,7 +2,8 @@ package conf
// WebRTCICEServer is a WebRTC ICE Server.
type WebRTCICEServer struct {
URL string `json:"url"`
Username string `json:"username"`
Password string `json:"password"`
URL string `json:"url"`
Username string `json:"username"`
Password string `json:"password"`
ClientOnly bool `json:"clientOnly"`
}

4
internal/servers/webrtc/http_server.go

@ -151,7 +151,7 @@ func (s *httpServer) onWHIPOptions(ctx *gin.Context, path string, publish bool) @@ -151,7 +151,7 @@ func (s *httpServer) onWHIPOptions(ctx *gin.Context, path string, publish bool)
return
}
servers, err := s.parent.generateICEServers()
servers, err := s.parent.generateICEServers(true)
if err != nil {
writeError(ctx, http.StatusInternalServerError, err)
return
@ -191,7 +191,7 @@ func (s *httpServer) onWHIPPost(ctx *gin.Context, path string, publish bool) { @@ -191,7 +191,7 @@ func (s *httpServer) onWHIPPost(ctx *gin.Context, path string, publish bool) {
return
}
servers, err := s.parent.generateICEServers()
servers, err := s.parent.generateICEServers(true)
if err != nil {
writeError(ctx, http.StatusInternalServerError, err)
return

38
internal/servers/webrtc/server.go

@ -429,30 +429,32 @@ func (s *Server) findSessionByUUID(uuid uuid.UUID) *session { @@ -429,30 +429,32 @@ func (s *Server) findSessionByUUID(uuid uuid.UUID) *session {
return nil
}
func (s *Server) generateICEServers() ([]pwebrtc.ICEServer, error) {
ret := make([]pwebrtc.ICEServer, len(s.ICEServers))
func (s *Server) generateICEServers(clientConfig bool) ([]pwebrtc.ICEServer, error) {
ret := make([]pwebrtc.ICEServer, 0, len(s.ICEServers))
for i, server := range s.ICEServers {
if server.Username == "AUTH_SECRET" {
expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix()
for _, server := range s.ICEServers {
if !server.ClientOnly || clientConfig {
if server.Username == "AUTH_SECRET" {
expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix()
user, err := randomTurnUser()
if err != nil {
return nil, err
}
user, err := randomTurnUser()
if err != nil {
return nil, err
}
server.Username = strconv.FormatInt(expireDate, 10) + ":" + user
server.Username = strconv.FormatInt(expireDate, 10) + ":" + user
h := hmac.New(sha1.New, []byte(server.Password))
h.Write([]byte(server.Username))
h := hmac.New(sha1.New, []byte(server.Password))
h.Write([]byte(server.Username))
server.Password = base64.StdEncoding.EncodeToString(h.Sum(nil))
}
server.Password = base64.StdEncoding.EncodeToString(h.Sum(nil))
}
ret[i] = pwebrtc.ICEServer{
URLs: []string{server.URL},
Username: server.Username,
Credential: server.Password,
ret = append(ret, pwebrtc.ICEServer{
URLs: []string{server.URL},
Username: server.Username,
Credential: server.Password,
})
}
}

37
internal/servers/webrtc/server_test.go

@ -408,3 +408,40 @@ func TestServerReadNotFound(t *testing.T) { @@ -408,3 +408,40 @@ func TestServerReadNotFound(t *testing.T) {
require.Equal(t, http.StatusNotFound, res.StatusCode)
}
func TestICEServerNoClientOnly(t *testing.T) {
s := &Server{
ICEServers: []conf.WebRTCICEServer{
{
URL: "turn:turn.example.com:1234",
Username: "user",
Password: "passwrd",
},
},
}
clientICEServers, err := s.generateICEServers(true)
require.NoError(t, err)
require.Equal(t, len(s.ICEServers), len(clientICEServers))
serverICEServers, err := s.generateICEServers(false)
require.NoError(t, err)
require.Equal(t, len(s.ICEServers), len(serverICEServers))
}
func TestICEServerClientOnly(t *testing.T) {
s := &Server{
ICEServers: []conf.WebRTCICEServer{
{
URL: "turn:turn.example.com:1234",
Username: "user",
Password: "passwrd",
ClientOnly: true,
},
},
}
clientICEServers, err := s.generateICEServers(true)
require.NoError(t, err)
require.Equal(t, len(s.ICEServers), len(clientICEServers))
serverICEServers, err := s.generateICEServers(false)
require.NoError(t, err)
require.Equal(t, 0, len(serverICEServers))
}

4
internal/servers/webrtc/session.go

@ -393,7 +393,7 @@ func (s *session) runPublish() (int, error) { @@ -393,7 +393,7 @@ func (s *session) runPublish() (int, error) {
defer path.RemovePublisher(defs.PathRemovePublisherReq{Author: s})
iceServers, err := s.parent.generateICEServers()
iceServers, err := s.parent.generateICEServers(false)
if err != nil {
return http.StatusInternalServerError, err
}
@ -528,7 +528,7 @@ func (s *session) runRead() (int, error) { @@ -528,7 +528,7 @@ func (s *session) runRead() (int, error) {
defer path.RemoveReader(defs.PathRemoveReaderReq{Author: s})
iceServers, err := s.parent.generateICEServers()
iceServers, err := s.parent.generateICEServers(false)
if err != nil {
return http.StatusInternalServerError, err
}

Loading…
Cancel
Save