forked from External/mediamtx
This commit is contained in:
parent
caa9fa6ca0
commit
39ae1269ad
3 changed files with 134 additions and 7 deletions
42
README.md
42
README.md
|
|
@ -134,7 +134,8 @@ _rtsp-simple-server_ has been rebranded as _MediaMTX_. The reason is pretty obvi
|
|||
* [SRT-specific features](#srt-specific-features)
|
||||
* [Standard stream ID syntax](#standard-stream-id-syntax)
|
||||
* [WebRTC-specific features](#webrtc-specific-features)
|
||||
* [Connectivity issues](#connectivity-issues)
|
||||
* [Authenticating with WHIP/WHEP](#authenticating-with-whipwhep)
|
||||
* [Solving WebRTC connectivity issues](#solving-webrtc-connectivity-issues)
|
||||
* [RTSP-specific features](#rtsp-specific-features)
|
||||
* [Transport protocols](#transport-protocols)
|
||||
* [Encryption](#encryption)
|
||||
|
|
@ -338,6 +339,7 @@ Latest versions of OBS Studio can publish to the server with the [WebRTC / WHIP
|
|||
|
||||
* Service: `WHIP`
|
||||
* Server: `http://localhost:8889/mystream/whip`
|
||||
* Bearer Token: `myuser:mypass` (if internal authentication is enabled) or JWT (if JWT-based authentication is enabled)
|
||||
|
||||
Save the configuration and click `Start streaming`.
|
||||
|
||||
|
|
@ -610,7 +612,9 @@ WHIP is a WebRTC extensions that allows to publish streams by using a URL, witho
|
|||
http://localhost:8889/mystream/whip
|
||||
```
|
||||
|
||||
Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations.
|
||||
Regarding authentication, read [Authenticating with WHIP/WHEP](#authenticating-with-whipwhep).
|
||||
|
||||
Depending on the network it may be difficult to establish a connection between server and clients, read [Solving WebRTC connectivity issues](#solving-webrtc-connectivity-issues).
|
||||
|
||||
Known clients that can publish with WebRTC and WHIP are [FFmpeg](#ffmpeg), [GStreamer](#gstreamer), [OBS Studio](#obs-studio).
|
||||
|
||||
|
|
@ -876,7 +880,9 @@ WHEP is a WebRTC extensions that allows to read streams by using a URL, without
|
|||
http://localhost:8889/mystream/whep
|
||||
```
|
||||
|
||||
Depending on the network it may be difficult to establish a connection between server and clients, see [WebRTC-specific features](#webrtc-specific-features) for remediations.
|
||||
Regarding authentication, read [Authenticating with WHIP/WHEP](#authenticating-with-whipwhep).
|
||||
|
||||
Depending on the network it may be difficult to establish a connection between server and clients, read [Solving WebRTC connectivity issues](#solving-webrtc-connectivity-issues).
|
||||
|
||||
Known clients that can read with WebRTC and WHEP are [FFmpeg](#ffmpeg-1), [GStreamer](#gstreamer-1) and [web browsers](#web-browsers-1).
|
||||
|
||||
|
|
@ -1838,7 +1844,35 @@ Where:
|
|||
|
||||
### WebRTC-specific features
|
||||
|
||||
#### Connectivity issues
|
||||
#### Authenticating with WHIP/WHEP
|
||||
|
||||
When using WHIP or WHEP to establish a WebRTC connection, there are multiple ways to provide credentials.
|
||||
|
||||
If internal authentication or HTTP-based authentication is enabled, username and password can be passed through the `Authentication: Basic` header:
|
||||
|
||||
```
|
||||
Authentication: Basic [base64_encoded_credentials]
|
||||
```
|
||||
|
||||
Username and password can be also passed through the `Authentication: Bearer` header (since it's mandated by the specification):
|
||||
|
||||
```
|
||||
Authentication: Bearer username:password
|
||||
```
|
||||
|
||||
If JWT-based authentication is enabled, JWT can be passed through the `Authentication: Bearer` header:
|
||||
|
||||
```
|
||||
Authentication: Bearer [jwt]
|
||||
```
|
||||
|
||||
The JWT can also be passed through query parameters:
|
||||
|
||||
```
|
||||
http://localhost:8889/mystream/whip?jwt=[jwt]
|
||||
```
|
||||
|
||||
#### Solving WebRTC connectivity issues
|
||||
|
||||
If the server is hosted inside a container or is behind a NAT, additional configuration is required in order to allow the two WebRTC parts (server and client) to establish a connection.
|
||||
|
||||
|
|
|
|||
|
|
@ -121,10 +121,17 @@ func (s *httpServer) close() {
|
|||
|
||||
func (s *httpServer) checkAuthOutsideSession(ctx *gin.Context, pathName string, publish bool) bool {
|
||||
user, pass, hasCredentials := ctx.Request.BasicAuth()
|
||||
|
||||
q := ctx.Request.URL.RawQuery
|
||||
|
||||
if h := ctx.Request.Header.Get("Authorization"); strings.HasPrefix(h, "Bearer ") {
|
||||
// JWT in authorization bearer -> JWT in query parameters
|
||||
q = addJWTFromAuthorization(q, h)
|
||||
|
||||
// credentials in authorization bearer -> credentials in authorization basic
|
||||
if parts := strings.Split(strings.TrimPrefix(h, "Bearer "), ":"); len(parts) == 2 {
|
||||
user = parts[0]
|
||||
pass = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
_, err := s.pathManager.FindPathConf(defs.PathFindPathConfReq{
|
||||
|
|
@ -194,10 +201,17 @@ func (s *httpServer) onWHIPPost(ctx *gin.Context, pathName string, publish bool)
|
|||
}
|
||||
|
||||
user, pass, _ := ctx.Request.BasicAuth()
|
||||
|
||||
q := ctx.Request.URL.RawQuery
|
||||
|
||||
if h := ctx.Request.Header.Get("Authorization"); strings.HasPrefix(h, "Bearer ") {
|
||||
// JWT in authorization bearer -> JWT in query parameters
|
||||
q = addJWTFromAuthorization(q, h)
|
||||
|
||||
// credentials in authorization bearer -> credentials in authorization basic
|
||||
if parts := strings.Split(strings.TrimPrefix(h, "Bearer "), ":"); len(parts) == 2 {
|
||||
user = parts[0]
|
||||
pass = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
res := s.parent.newSession(webRTCNewSessionReq{
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ func TestServerRead(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServerReadAuthorizationHeader(t *testing.T) {
|
||||
func TestServerReadAuthorizationBearerJWT(t *testing.T) {
|
||||
desc := &description.Session{Medias: []*description.Media{test.MediaH264}}
|
||||
|
||||
str, err := stream.New(
|
||||
|
|
@ -680,6 +680,85 @@ func TestServerReadAuthorizationHeader(t *testing.T) {
|
|||
require.Equal(t, http.StatusCreated, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestServerReadAuthorizationUserPass(t *testing.T) {
|
||||
desc := &description.Session{Medias: []*description.Media{test.MediaH264}}
|
||||
|
||||
str, err := stream.New(
|
||||
1460,
|
||||
desc,
|
||||
true,
|
||||
test.NilLogger,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
path := &dummyPath{stream: str}
|
||||
|
||||
pm := &dummyPathManager{
|
||||
findPathConf: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||
require.Equal(t, "myuser", req.AccessRequest.User)
|
||||
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
||||
return &conf.Path{}, nil
|
||||
},
|
||||
addReader: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||
require.Equal(t, "myuser", req.AccessRequest.User)
|
||||
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
||||
return path, str, nil
|
||||
},
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Address: "127.0.0.1:8886",
|
||||
Encryption: false,
|
||||
ServerKey: "",
|
||||
ServerCert: "",
|
||||
AllowOrigin: "",
|
||||
TrustedProxies: conf.IPNetworks{},
|
||||
ReadTimeout: conf.StringDuration(10 * time.Second),
|
||||
WriteQueueSize: 512,
|
||||
LocalUDPAddress: "127.0.0.1:8887",
|
||||
LocalTCPAddress: "127.0.0.1:8887",
|
||||
IPsFromInterfaces: true,
|
||||
IPsFromInterfacesList: []string{},
|
||||
AdditionalHosts: []string{},
|
||||
ICEServers: []conf.WebRTCICEServer{},
|
||||
HandshakeTimeout: conf.StringDuration(10 * time.Second),
|
||||
TrackGatherTimeout: conf.StringDuration(2 * time.Second),
|
||||
ExternalCmdPool: nil,
|
||||
PathManager: pm,
|
||||
Parent: test.NilLogger,
|
||||
}
|
||||
err = s.Initialize()
|
||||
require.NoError(t, err)
|
||||
defer s.Close()
|
||||
|
||||
tr := &http.Transport{}
|
||||
defer tr.CloseIdleConnections()
|
||||
hc := &http.Client{Transport: tr}
|
||||
|
||||
pc, err := pwebrtc.NewPeerConnection(pwebrtc.Configuration{})
|
||||
require.NoError(t, err)
|
||||
defer pc.Close() //nolint:errcheck
|
||||
|
||||
_, err = pc.AddTransceiverFromKind(pwebrtc.RTPCodecTypeVideo)
|
||||
require.NoError(t, err)
|
||||
|
||||
offer, err := pc.CreateOffer(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost,
|
||||
"http://localhost:8886/teststream/whep", bytes.NewReader([]byte(offer.SDP)))
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", "application/sdp")
|
||||
req.Header.Set("Authorization", "Bearer myuser:mypass")
|
||||
|
||||
res, err := hc.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer res.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusCreated, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestServerReadNotFound(t *testing.T) {
|
||||
pm := &dummyPathManager{
|
||||
findPathConf: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue