forked from External/mediamtx
Add option for ICE servers to be client only (#3164)
* Add option for ICE servers to be client only * add clientOnly to configuration file and API docs --------- Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
parent
60e7d77e41
commit
87c0535823
8 changed files with 80 additions and 27 deletions
10
README.md
10
README.md
|
|
@ -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.
|
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
|
### RTSP-specific features
|
||||||
|
|
||||||
#### Transport protocols
|
#### Transport protocols
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,8 @@ components:
|
||||||
type: string
|
type: string
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
|
clientOnly:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
# SRT server
|
# SRT server
|
||||||
srt:
|
srt:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ package conf
|
||||||
|
|
||||||
// WebRTCICEServer is a WebRTC ICE Server.
|
// WebRTCICEServer is a WebRTC ICE Server.
|
||||||
type WebRTCICEServer struct {
|
type WebRTCICEServer struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
ClientOnly bool `json:"clientOnly"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ func (s *httpServer) onWHIPOptions(ctx *gin.Context, path string, publish bool)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
servers, err := s.parent.generateICEServers()
|
servers, err := s.parent.generateICEServers(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, http.StatusInternalServerError, err)
|
writeError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
@ -191,7 +191,7 @@ func (s *httpServer) onWHIPPost(ctx *gin.Context, path string, publish bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
servers, err := s.parent.generateICEServers()
|
servers, err := s.parent.generateICEServers(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, http.StatusInternalServerError, err)
|
writeError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -429,30 +429,32 @@ func (s *Server) findSessionByUUID(uuid uuid.UUID) *session {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) generateICEServers() ([]pwebrtc.ICEServer, error) {
|
func (s *Server) generateICEServers(clientConfig bool) ([]pwebrtc.ICEServer, error) {
|
||||||
ret := make([]pwebrtc.ICEServer, len(s.ICEServers))
|
ret := make([]pwebrtc.ICEServer, 0, len(s.ICEServers))
|
||||||
|
|
||||||
for i, server := range s.ICEServers {
|
for _, server := range s.ICEServers {
|
||||||
if server.Username == "AUTH_SECRET" {
|
if !server.ClientOnly || clientConfig {
|
||||||
expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix()
|
if server.Username == "AUTH_SECRET" {
|
||||||
|
expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix()
|
||||||
|
|
||||||
user, err := randomTurnUser()
|
user, err := randomTurnUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
server.Username = strconv.FormatInt(expireDate, 10) + ":" + user
|
||||||
|
|
||||||
|
h := hmac.New(sha1.New, []byte(server.Password))
|
||||||
|
h.Write([]byte(server.Username))
|
||||||
|
|
||||||
|
server.Password = base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Username = strconv.FormatInt(expireDate, 10) + ":" + user
|
ret = append(ret, pwebrtc.ICEServer{
|
||||||
|
URLs: []string{server.URL},
|
||||||
h := hmac.New(sha1.New, []byte(server.Password))
|
Username: server.Username,
|
||||||
h.Write([]byte(server.Username))
|
Credential: server.Password,
|
||||||
|
})
|
||||||
server.Password = base64.StdEncoding.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[i] = pwebrtc.ICEServer{
|
|
||||||
URLs: []string{server.URL},
|
|
||||||
Username: server.Username,
|
|
||||||
Credential: server.Password,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -408,3 +408,40 @@ func TestServerReadNotFound(t *testing.T) {
|
||||||
|
|
||||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
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))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ func (s *session) runPublish() (int, error) {
|
||||||
|
|
||||||
defer path.RemovePublisher(defs.PathRemovePublisherReq{Author: s})
|
defer path.RemovePublisher(defs.PathRemovePublisherReq{Author: s})
|
||||||
|
|
||||||
iceServers, err := s.parent.generateICEServers()
|
iceServers, err := s.parent.generateICEServers(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +528,7 @@ func (s *session) runRead() (int, error) {
|
||||||
|
|
||||||
defer path.RemoveReader(defs.PathRemoveReaderReq{Author: s})
|
defer path.RemoveReader(defs.PathRemoveReaderReq{Author: s})
|
||||||
|
|
||||||
iceServers, err := s.parent.generateICEServers()
|
iceServers, err := s.parent.generateICEServers(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,7 @@ webrtcICEServers2: []
|
||||||
# the secret must be inserted into the password field.
|
# the secret must be inserted into the password field.
|
||||||
# username: ''
|
# username: ''
|
||||||
# password: ''
|
# password: ''
|
||||||
|
# clientOnly: false
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# Global settings -> SRT server
|
# Global settings -> SRT server
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue