Browse Source

webrtc: improve connectivity mechanism (#2686)

pull/2687/head
Alessandro Ros 2 years ago committed by GitHub
parent
commit
687d8685ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      README.md
  2. 26
      apidocs/openapi.yaml
  3. 6
      go.mod
  4. 32
      go.sum
  5. 60
      internal/conf/conf.go
  6. 2
      internal/conf/encryption.go
  7. 52
      internal/core/core.go
  8. 4
      internal/core/path.go
  9. 157
      internal/core/webrtc_manager.go
  10. 44
      internal/protocols/webrtc/api.go
  11. 10
      internal/protocols/webrtc/whip_client.go
  12. 5
      internal/staticsources/webrtc/source_test.go
  13. 50
      mediamtx.yml

37
README.md

@ -170,14 +170,18 @@ The `--network=host` flag is mandatory since Docker can change the source port o
``` ```
docker run --rm -it \ docker run --rm -it \
-e MTX_PROTOCOLS=tcp \ -e MTX_PROTOCOLS=tcp \
-e MTX_WEBRTCADDITIONALHOSTS=192.168.x.x \
-p 8554:8554 \ -p 8554:8554 \
-p 1935:1935 \ -p 1935:1935 \
-p 8888:8888 \ -p 8888:8888 \
-p 8889:8889 \ -p 8889:8889 \
-p 8890:8890/udp \ -p 8890:8890/udp \
-p 8189:8189/udp \
bluenviron/mediamtx bluenviron/mediamtx
``` ```
set `MTX_WEBRTCADDITIONALHOSTS` to your local IP address.
### Arch Linux package ### Arch Linux package
If you are running the Arch Linux distribution, run: If you are running the Arch Linux distribution, run:
@ -1596,18 +1600,15 @@ Be aware that RTMPS is currently unsupported by all major players. However, you
#### Connectivity issues #### 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 (the browser and the server) to establish a connection (WebRTC/ICE connection). 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.
A first method consists into forcing all WebRTC/ICE connections to pass through a single UDP server port, by using the parameters: Make sure that `webrtcAdditionalHosts` includes your public IP, that is the IP that can be used by clients to reach the server. If clients are on the same LAN as the server, then it's the LAN address of the server, otherwise it's the public internet IP of the server:
```yml ```yml
# public IP of the server webrtcAdditionalHosts: [192.168.x.x]
webrtcICEHostNAT1To1IPs: [192.168.x.x]
# any port of choice
webrtcICEUDPMuxAddress: :8189
``` ```
The NAT / container must then be configured in order to route all incoming UDP packets on port 8189 to the server. If you're using Docker, this can be achieved with the flag: If there's a NAT / container between server and clients, it must be configured to route all incoming UDP packets on port 8189 to the server. If you're using Docker, this can be achieved with the flag:
```sh ```sh
docker run --rm -it \ docker run --rm -it \
@ -1616,27 +1617,27 @@ docker run --rm -it \
bluenviron/mediamtx bluenviron/mediamtx
``` ```
If the UDP protocol is blocked by a firewall, all WebRTC/ICE connections can be forced to pass through a single TCP server port: If you still have problems, maybe the UDP protocol is blocked by a firewall. Enable the local TCP listener:
```yml ```yml
# public IP of the server
webrtcICEHostNAT1To1IPs: [192.168.x.x]
# any port of choice # any port of choice
webrtcICETCPMuxAddress: :8189 webrtcLocalTCPAddress: :8189
``` ```
The NAT / container must then be configured in order to redirect all incoming TCP packets on port 8189 to the server. If you're using Docker, this can be achieved with the flag: If there's a NAT / container between server and clients, it must be configured to route all incoming TCP packets on port 8189 to the server.
```sh If you still have problems, enable a STUN server:
docker run --rm -it \
-p 8189:8189 ```yml
.... # STUN servers allows to obtain and share the public IP of the server.
bluenviron/mediamtx webrtcICEServers2:
- url: stun:stun.l.google.com:19302
``` ```
Finally, if none of these methods work, you can force all WebRTC/ICE connections to pass through a TURN server, like coturn, that must be configured externally. The server address and credentials must be set in the configuration file: If you really still have problems, you can force all WebRTC/ICE connections to pass through a TURN server, like coturn, that must be configured externally. The server address and credentials must be set in the configuration file:
```yml ```yml
# TURN/TURNS servers forces all traffic through them.
webrtcICEServers2: webrtcICEServers2:
- url: turn:host:port - url: turn:host:port
username: user username: user

26
apidocs/openapi.yaml

@ -157,6 +157,20 @@ components:
type: array type: array
items: items:
type: string type: string
webrtcLocalUDPAddress:
type: string
webrtcLocalTCPAddress:
type: string
webrtcIPsFromInterfaces:
type: boolean
webrtcIPsFromInterfacesList:
type: array
items:
type: string
webrtcAdditionalHosts:
type: array
items:
type: string
webrtcICEServers2: webrtcICEServers2:
type: array type: array
items: items:
@ -168,18 +182,6 @@ components:
type: string type: string
password: password:
type: string type: string
webrtcICEInterfaces:
type: array
items:
type: string
webrtcICEHostNAT1To1IPs:
type: array
items:
type: string
webrtcICEUDPMuxAddress:
type: string
webrtcICETCPMuxAddress:
type: string
# SRT # SRT
srt: srt:

6
go.mod

@ -53,7 +53,7 @@ require (
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pion/datachannel v1.5.5 // indirect github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/mdns v0.0.8 // indirect github.com/pion/mdns v0.0.9 // indirect
github.com/pion/randutil v0.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect
github.com/pion/sctp v1.8.8 // indirect github.com/pion/sctp v1.8.8 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect github.com/pion/srtp/v2 v2.0.18 // indirect
@ -76,4 +76,8 @@ replace code.cloudfoundry.org/bytefmt => github.com/cloudfoundry/bytefmt v0.0.0-
replace github.com/pion/sdp/v3 => github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326 replace github.com/pion/sdp/v3 => github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326
replace github.com/pion/ice/v2 => github.com/aler9/ice/v2 v2.0.0-20231112223552-32d34dfcf3a1
replace github.com/pion/webrtc/v3 => github.com/aler9/webrtc/v3 v3.0.0-20231112223655-e402ed2689c6
replace github.com/datarhei/gosrt => github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d replace github.com/datarhei/gosrt => github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d

32
go.sum

@ -8,8 +8,12 @@ github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d h1:e+oBFUPyjr6dYd4lmT3+NI0lQVpr6R7nTO6z+1XGceQ= github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d h1:e+oBFUPyjr6dYd4lmT3+NI0lQVpr6R7nTO6z+1XGceQ=
github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d/go.mod h1:z+FuFVKH0eG03LwuMwVrOLlWhPlpbRlL2OytRK+hs5c= github.com/aler9/gosrt v0.0.0-20231104205907-3f110868f71d/go.mod h1:z+FuFVKH0eG03LwuMwVrOLlWhPlpbRlL2OytRK+hs5c=
github.com/aler9/ice/v2 v2.0.0-20231112223552-32d34dfcf3a1 h1:fD6eZt+3/t8bzFn6ZZA2eP63xBP06v3EPfPJu8DO8ys=
github.com/aler9/ice/v2 v2.0.0-20231112223552-32d34dfcf3a1/go.mod h1:lT3kv5uUIlHfXHU/ZRD7uKD/ufM202+eTa3C/umgGf4=
github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326 h1:HA7u47vkcxFiHtiOjm8srh1JRgC0ZPYefPtpDCaTtS0= github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326 h1:HA7u47vkcxFiHtiOjm8srh1JRgC0ZPYefPtpDCaTtS0=
github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326/go.mod h1:I40uD/ZSmK2peI6AdJga5fd55d4bFK0oWOgLS9Q8sVc= github.com/aler9/sdp/v3 v3.0.0-20231022165400-33437e07f326/go.mod h1:I40uD/ZSmK2peI6AdJga5fd55d4bFK0oWOgLS9Q8sVc=
github.com/aler9/webrtc/v3 v3.0.0-20231112223655-e402ed2689c6 h1:wMd3D1mLghoYYh31STig8Kwm2qi8QyQKUy09qUUZrVw=
github.com/aler9/webrtc/v3 v3.0.0-20231112223655-e402ed2689c6/go.mod h1:1CaT2fcZzZ6VZA+O1i9yK2DU4EOcXVvSbWG9pr5jefs=
github.com/aler9/writerseeker v1.1.0 h1:t+Sm3tjp8scNlqyoa8obpeqwciMNOvdvsxjxEb3Sx3g= github.com/aler9/writerseeker v1.1.0 h1:t+Sm3tjp8scNlqyoa8obpeqwciMNOvdvsxjxEb3Sx3g=
github.com/aler9/writerseeker v1.1.0/go.mod h1:QNCcjSKnLsYoTfMmXkEEfgbz6nNXWxKSaBY+hGJGWDA= github.com/aler9/writerseeker v1.1.0/go.mod h1:QNCcjSKnLsYoTfMmXkEEfgbz6nNXWxKSaBY+hGJGWDA=
github.com/asticode/go-astikit v0.30.0 h1:DkBkRQRIxYcknlaU7W7ksNfn4gMFsB0tqMJflxkRsZA= github.com/asticode/go-astikit v0.30.0 h1:DkBkRQRIxYcknlaU7W7ksNfn4gMFsB0tqMJflxkRsZA=
@ -73,7 +77,7 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
@ -128,14 +132,13 @@ github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0= github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/ice/v2 v2.3.11 h1:rZjVmUwyT55cmN8ySMpL7rsS8KYsJERsrxJLLxpKhdw=
github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc= github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc=
github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y= github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.8 h1:HhicWIg7OX5PVilyBO6plhMetInbzkVJAhbdJiAeVaI= github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSyaI= github.com/pion/mdns v0.0.9 h1:7Ue5KZsqq8EuqStnpPWV33vYYEH0+skdDN5L7EiEsI4=
github.com/pion/mdns v0.0.9/go.mod h1:2JA5exfxwzXiCihmxpTKgFUpiQws2MnipoPK09vecIc=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I= github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
@ -153,16 +156,15 @@ github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40= github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI= github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
github.com/pion/transport/v2 v2.2.3 h1:XcOE3/x41HOSKbl1BfyY1TF1dERx7lVvlMCbXU7kfvA= github.com/pion/transport/v2 v2.2.3 h1:XcOE3/x41HOSKbl1BfyY1TF1dERx7lVvlMCbXU7kfvA=
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
github.com/pion/turn/v2 v2.1.2/go.mod h1:1kjnPkBcex3dhCU2Am+AAmxDcGhLX3WnMfmkNpvSTQU=
github.com/pion/turn/v2 v2.1.3 h1:pYxTVWG2gpC97opdRc5IGsQ1lJ9O/IlNhkzj7MMrGAA= github.com/pion/turn/v2 v2.1.3 h1:pYxTVWG2gpC97opdRc5IGsQ1lJ9O/IlNhkzj7MMrGAA=
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/webrtc/v3 v3.2.22 h1:Hno262T7+V56MgUO30O0ZirZmVSvbXtnau31SB0WSpc=
github.com/pion/webrtc/v3 v3.2.22/go.mod h1:1CaT2fcZzZ6VZA+O1i9yK2DU4EOcXVvSbWG9pr5jefs=
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE= github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -199,8 +201,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -215,12 +217,13 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -246,24 +249,26 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -271,11 +276,12 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

60
internal/conf/conf.go

@ -143,20 +143,24 @@ type Conf struct {
HLSDirectory string `json:"hlsDirectory"` HLSDirectory string `json:"hlsDirectory"`
// WebRTC // WebRTC
WebRTC bool `json:"webrtc"` WebRTC bool `json:"webrtc"`
WebRTCDisable *bool `json:"webrtcDisable,omitempty"` // deprecated WebRTCDisable *bool `json:"webrtcDisable,omitempty"` // deprecated
WebRTCAddress string `json:"webrtcAddress"` WebRTCAddress string `json:"webrtcAddress"`
WebRTCEncryption bool `json:"webrtcEncryption"` WebRTCEncryption bool `json:"webrtcEncryption"`
WebRTCServerKey string `json:"webrtcServerKey"` WebRTCServerKey string `json:"webrtcServerKey"`
WebRTCServerCert string `json:"webrtcServerCert"` WebRTCServerCert string `json:"webrtcServerCert"`
WebRTCAllowOrigin string `json:"webrtcAllowOrigin"` WebRTCAllowOrigin string `json:"webrtcAllowOrigin"`
WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"` WebRTCTrustedProxies IPsOrCIDRs `json:"webrtcTrustedProxies"`
WebRTCICEServers *[]string `json:"webrtcICEServers,omitempty"` // deprecated WebRTCLocalUDPAddress string `json:"webrtcLocalUDPAddress"`
WebRTCICEServers2 []WebRTCICEServer `json:"webrtcICEServers2"` WebRTCLocalTCPAddress string `json:"webrtcLocalTCPAddress"`
WebRTCICEInterfaces []string `json:"webrtcICEInterfaces"` WebRTCIPsFromInterfaces bool `json:"webrtcIPsFromInterfaces"`
WebRTCICEHostNAT1To1IPs []string `json:"webrtcICEHostNAT1To1IPs"` WebRTCIPsFromInterfacesList []string `json:"webrtcIPsFromInterfacesList"`
WebRTCICEUDPMuxAddress string `json:"webrtcICEUDPMuxAddress"` WebRTCAdditionalHosts []string `json:"webrtcAdditionalHosts"`
WebRTCICETCPMuxAddress string `json:"webrtcICETCPMuxAddress"` WebRTCICEServers2 []WebRTCICEServer `json:"webrtcICEServers2"`
WebRTCICEUDPMuxAddress *string `json:"webrtcICEUDPMuxAddress,omitempty"` // deprecated
WebRTCICETCPMuxAddress *string `json:"webrtcICETCPMuxAddress,omitempty"` // deprecated
WebRTCICEHostNAT1To1IPs *[]string `json:"webrtcICEHostNAT1To1IPs,omitempty"` // deprecated
WebRTCICEServers *[]string `json:"webrtcICEServers,omitempty"` // deprecated
// SRT // SRT
SRT bool `json:"srt"` SRT bool `json:"srt"`
@ -234,9 +238,11 @@ func (conf *Conf) setDefaults() {
conf.WebRTCServerKey = "server.key" conf.WebRTCServerKey = "server.key"
conf.WebRTCServerCert = "server.crt" conf.WebRTCServerCert = "server.crt"
conf.WebRTCAllowOrigin = "*" conf.WebRTCAllowOrigin = "*"
conf.WebRTCICEServers2 = []WebRTCICEServer{{URL: "stun:stun.l.google.com:19302"}} conf.WebRTCLocalUDPAddress = ":8189"
conf.WebRTCICEInterfaces = []string{} conf.WebRTCIPsFromInterfaces = true
conf.WebRTCICEHostNAT1To1IPs = []string{} conf.WebRTCIPsFromInterfacesList = []string{}
conf.WebRTCAdditionalHosts = []string{}
conf.WebRTCICEServers2 = []WebRTCICEServer{}
// SRT // SRT
conf.SRT = true conf.SRT = true
@ -382,6 +388,15 @@ func (conf *Conf) Check() error {
if conf.WebRTCDisable != nil { if conf.WebRTCDisable != nil {
conf.WebRTC = !*conf.WebRTCDisable conf.WebRTC = !*conf.WebRTCDisable
} }
if conf.WebRTCICEUDPMuxAddress != nil {
conf.WebRTCLocalUDPAddress = *conf.WebRTCICEUDPMuxAddress
}
if conf.WebRTCICETCPMuxAddress != nil {
conf.WebRTCLocalTCPAddress = *conf.WebRTCICETCPMuxAddress
}
if conf.WebRTCICEHostNAT1To1IPs != nil {
conf.WebRTCAdditionalHosts = *conf.WebRTCICEHostNAT1To1IPs
}
if conf.WebRTCICEServers != nil { if conf.WebRTCICEServers != nil {
for _, server := range *conf.WebRTCICEServers { for _, server := range *conf.WebRTCICEServers {
parts := strings.Split(server, ":") parts := strings.Split(server, ":")
@ -405,6 +420,17 @@ func (conf *Conf) Check() error {
return fmt.Errorf("invalid ICE server: '%s'", server.URL) return fmt.Errorf("invalid ICE server: '%s'", server.URL)
} }
} }
if conf.WebRTCLocalUDPAddress == "" &&
conf.WebRTCLocalTCPAddress == "" &&
len(conf.WebRTCICEServers2) == 0 {
return fmt.Errorf("at least one between 'webrtcLocalUDPAddress'," +
" 'webrtcLocalTCPAddress' or 'webrtcICEServers2' must be filled")
}
if conf.WebRTCLocalUDPAddress != "" || conf.WebRTCLocalTCPAddress != "" {
if !conf.WebRTCIPsFromInterfaces && len(conf.WebRTCAdditionalHosts) == 0 {
return fmt.Errorf("at least one between 'webrtcIPsFromInterfaces' or 'webrtcAdditionalHosts' must be filled")
}
}
// Record // Record
if conf.Record != nil { if conf.Record != nil {

2
internal/conf/encryption.go

@ -8,7 +8,7 @@ import (
// Encryption is the encryption parameter. // Encryption is the encryption parameter.
type Encryption int type Encryption int
// supported encryption policies. // values.
const ( const (
EncryptionNo Encryption = iota EncryptionNo Encryption = iota
EncryptionOptional EncryptionOptional

52
internal/core/core.go

@ -472,26 +472,29 @@ func (p *Core) createResources(initial bool) error {
if p.conf.WebRTC && if p.conf.WebRTC &&
p.webRTCManager == nil { p.webRTCManager == nil {
p.webRTCManager, err = newWebRTCManager( p.webRTCManager = &webRTCManager{
p.conf.WebRTCAddress, Address: p.conf.WebRTCAddress,
p.conf.WebRTCEncryption, Encryption: p.conf.WebRTCEncryption,
p.conf.WebRTCServerKey, ServerKey: p.conf.WebRTCServerKey,
p.conf.WebRTCServerCert, ServerCert: p.conf.WebRTCServerCert,
p.conf.WebRTCAllowOrigin, AllowOrigin: p.conf.WebRTCAllowOrigin,
p.conf.WebRTCTrustedProxies, TrustedProxies: p.conf.WebRTCTrustedProxies,
p.conf.WebRTCICEServers2, ReadTimeout: p.conf.ReadTimeout,
p.conf.ReadTimeout, WriteQueueSize: p.conf.WriteQueueSize,
p.conf.WriteQueueSize, LocalUDPAddress: p.conf.WebRTCLocalUDPAddress,
p.conf.WebRTCICEInterfaces, LocalTCPAddress: p.conf.WebRTCLocalTCPAddress,
p.conf.WebRTCICEHostNAT1To1IPs, IPsFromInterfaces: p.conf.WebRTCIPsFromInterfaces,
p.conf.WebRTCICEUDPMuxAddress, IPsFromInterfacesList: p.conf.WebRTCIPsFromInterfacesList,
p.conf.WebRTCICETCPMuxAddress, AdditionalHosts: p.conf.WebRTCAdditionalHosts,
p.externalCmdPool, ICEServers: p.conf.WebRTCICEServers2,
p.pathManager, ExternalCmdPool: p.externalCmdPool,
p.metrics, PathManager: p.pathManager,
p, Metrics: p.metrics,
) Parent: p,
}
err = p.webRTCManager.initialize()
if err != nil { if err != nil {
p.webRTCManager = nil
return err return err
} }
} }
@ -689,13 +692,14 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.WebRTCServerCert != p.conf.WebRTCServerCert || newConf.WebRTCServerCert != p.conf.WebRTCServerCert ||
newConf.WebRTCAllowOrigin != p.conf.WebRTCAllowOrigin || newConf.WebRTCAllowOrigin != p.conf.WebRTCAllowOrigin ||
!reflect.DeepEqual(newConf.WebRTCTrustedProxies, p.conf.WebRTCTrustedProxies) || !reflect.DeepEqual(newConf.WebRTCTrustedProxies, p.conf.WebRTCTrustedProxies) ||
!reflect.DeepEqual(newConf.WebRTCICEServers2, p.conf.WebRTCICEServers2) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteQueueSize != p.conf.WriteQueueSize || newConf.WriteQueueSize != p.conf.WriteQueueSize ||
!reflect.DeepEqual(newConf.WebRTCICEInterfaces, p.conf.WebRTCICEInterfaces) || newConf.WebRTCLocalUDPAddress != p.conf.WebRTCLocalUDPAddress ||
!reflect.DeepEqual(newConf.WebRTCICEHostNAT1To1IPs, p.conf.WebRTCICEHostNAT1To1IPs) || newConf.WebRTCLocalTCPAddress != p.conf.WebRTCLocalTCPAddress ||
newConf.WebRTCICEUDPMuxAddress != p.conf.WebRTCICEUDPMuxAddress || newConf.WebRTCIPsFromInterfaces != p.conf.WebRTCIPsFromInterfaces ||
newConf.WebRTCICETCPMuxAddress != p.conf.WebRTCICETCPMuxAddress || !reflect.DeepEqual(newConf.WebRTCIPsFromInterfacesList, p.conf.WebRTCIPsFromInterfacesList) ||
!reflect.DeepEqual(newConf.WebRTCAdditionalHosts, p.conf.WebRTCAdditionalHosts) ||
!reflect.DeepEqual(newConf.WebRTCICEServers2, p.conf.WebRTCICEServers2) ||
closeMetrics || closeMetrics ||
closePathManager || closePathManager ||
closeLogger closeLogger

4
internal/core/path.go

@ -376,10 +376,6 @@ func (pa *path) runInner() error {
case <-pa.onDemandPublisherCloseTimer.C: case <-pa.onDemandPublisherCloseTimer.C:
pa.doOnDemandPublisherCloseTimer() pa.doOnDemandPublisherCloseTimer()
if pa.shouldClose() {
return fmt.Errorf("not in use")
}
case newConf := <-pa.chReloadConf: case newConf := <-pa.chReloadConf:
pa.doReloadConf(newConf) pa.doReloadConf(newConf)

157
internal/core/webrtc_manager.go

@ -15,7 +15,6 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pion/ice/v2"
"github.com/pion/logging" "github.com/pion/logging"
pwebrtc "github.com/pion/webrtc/v3" pwebrtc "github.com/pion/webrtc/v3"
@ -165,14 +164,24 @@ type webRTCManagerParent interface {
} }
type webRTCManager struct { type webRTCManager struct {
allowOrigin string Address string
trustedProxies conf.IPsOrCIDRs Encryption bool
iceServers []conf.WebRTCICEServer ServerKey string
writeQueueSize int ServerCert string
externalCmdPool *externalcmd.Pool AllowOrigin string
pathManager *pathManager TrustedProxies conf.IPsOrCIDRs
metrics *metrics ReadTimeout conf.StringDuration
parent webRTCManagerParent WriteQueueSize int
LocalUDPAddress string
LocalTCPAddress string
IPsFromInterfaces bool
IPsFromInterfacesList []string
AdditionalHosts []string
ICEServers []conf.WebRTCICEServer
ExternalCmdPool *externalcmd.Pool
PathManager *pathManager
Metrics *metrics
Parent webRTCManagerParent
ctx context.Context ctx context.Context
ctxCancel func() ctxCancel func()
@ -196,127 +205,97 @@ type webRTCManager struct {
done chan struct{} done chan struct{}
} }
func newWebRTCManager( func (m *webRTCManager) initialize() error {
address string,
encryption bool,
serverKey string,
serverCert string,
allowOrigin string,
trustedProxies conf.IPsOrCIDRs,
iceServers []conf.WebRTCICEServer,
readTimeout conf.StringDuration,
writeQueueSize int,
iceInterfaces []string,
iceHostNAT1To1IPs []string,
iceUDPMuxAddress string,
iceTCPMuxAddress string,
externalCmdPool *externalcmd.Pool,
pathManager *pathManager,
metrics *metrics,
parent webRTCManagerParent,
) (*webRTCManager, error) {
ctx, ctxCancel := context.WithCancel(context.Background()) ctx, ctxCancel := context.WithCancel(context.Background())
m := &webRTCManager{ m.ctx = ctx
allowOrigin: allowOrigin, m.ctxCancel = ctxCancel
trustedProxies: trustedProxies, m.sessions = make(map[*webRTCSession]struct{})
iceServers: iceServers, m.sessionsBySecret = make(map[uuid.UUID]*webRTCSession)
writeQueueSize: writeQueueSize, m.chNewSession = make(chan webRTCNewSessionReq)
externalCmdPool: externalCmdPool, m.chCloseSession = make(chan *webRTCSession)
pathManager: pathManager, m.chAddSessionCandidates = make(chan webRTCAddSessionCandidatesReq)
metrics: metrics, m.chDeleteSession = make(chan webRTCDeleteSessionReq)
parent: parent, m.chAPISessionsList = make(chan webRTCManagerAPISessionsListReq)
ctx: ctx, m.chAPISessionsGet = make(chan webRTCManagerAPISessionsGetReq)
ctxCancel: ctxCancel, m.chAPIConnsKick = make(chan webRTCManagerAPISessionsKickReq)
sessions: make(map[*webRTCSession]struct{}), m.done = make(chan struct{})
sessionsBySecret: make(map[uuid.UUID]*webRTCSession),
chNewSession: make(chan webRTCNewSessionReq),
chCloseSession: make(chan *webRTCSession),
chAddSessionCandidates: make(chan webRTCAddSessionCandidatesReq),
chDeleteSession: make(chan webRTCDeleteSessionReq),
chAPISessionsList: make(chan webRTCManagerAPISessionsListReq),
chAPISessionsGet: make(chan webRTCManagerAPISessionsGetReq),
chAPIConnsKick: make(chan webRTCManagerAPISessionsKickReq),
done: make(chan struct{}),
}
var err error var err error
m.httpServer, err = newWebRTCHTTPServer( m.httpServer, err = newWebRTCHTTPServer(
address, m.Address,
encryption, m.Encryption,
serverKey, m.ServerKey,
serverCert, m.ServerCert,
allowOrigin, m.AllowOrigin,
trustedProxies, m.TrustedProxies,
readTimeout, m.ReadTimeout,
pathManager, m.PathManager,
m, m,
) )
if err != nil { if err != nil {
ctxCancel() ctxCancel()
return nil, err return err
} }
var iceUDPMux ice.UDPMux apiConf := webrtc.APIConf{
LocalRandomUDP: false,
IPsFromInterfaces: m.IPsFromInterfaces,
IPsFromInterfacesList: m.IPsFromInterfacesList,
AdditionalHosts: m.AdditionalHosts,
}
if iceUDPMuxAddress != "" { if m.LocalUDPAddress != "" {
m.udpMuxLn, err = net.ListenPacket(restrictnetwork.Restrict("udp", iceUDPMuxAddress)) m.udpMuxLn, err = net.ListenPacket(restrictnetwork.Restrict("udp", m.LocalUDPAddress))
if err != nil { if err != nil {
m.httpServer.close() m.httpServer.close()
ctxCancel() ctxCancel()
return nil, err return err
} }
iceUDPMux = pwebrtc.NewICEUDPMux(webrtcNilLogger, m.udpMuxLn) apiConf.ICEUDPMux = pwebrtc.NewICEUDPMux(webrtcNilLogger, m.udpMuxLn)
} }
var iceTCPMux ice.TCPMux if m.LocalTCPAddress != "" {
m.tcpMuxLn, err = net.Listen(restrictnetwork.Restrict("tcp", m.LocalTCPAddress))
if iceTCPMuxAddress != "" {
m.tcpMuxLn, err = net.Listen(restrictnetwork.Restrict("tcp", iceTCPMuxAddress))
if err != nil { if err != nil {
m.udpMuxLn.Close() m.udpMuxLn.Close()
m.httpServer.close() m.httpServer.close()
ctxCancel() ctxCancel()
return nil, err return err
} }
iceTCPMux = pwebrtc.NewICETCPMux(webrtcNilLogger, m.tcpMuxLn, 8) apiConf.ICETCPMux = pwebrtc.NewICETCPMux(webrtcNilLogger, m.tcpMuxLn, 8)
} }
m.api, err = webrtc.NewAPI(webrtc.APIConf{ m.api, err = webrtc.NewAPI(apiConf)
ICEInterfaces: iceInterfaces,
ICEHostNAT1To1IPs: iceHostNAT1To1IPs,
ICEUDPMux: iceUDPMux,
ICETCPMux: iceTCPMux,
})
if err != nil { if err != nil {
m.udpMuxLn.Close() m.udpMuxLn.Close()
m.tcpMuxLn.Close() m.tcpMuxLn.Close()
m.httpServer.close() m.httpServer.close()
ctxCancel() ctxCancel()
return nil, err return err
} }
str := "listener opened on " + address + " (HTTP)" str := "listener opened on " + m.Address + " (HTTP)"
if m.udpMuxLn != nil { if m.udpMuxLn != nil {
str += ", " + iceUDPMuxAddress + " (ICE/UDP)" str += ", " + m.LocalUDPAddress + " (ICE/UDP)"
} }
if m.tcpMuxLn != nil { if m.tcpMuxLn != nil {
str += ", " + iceTCPMuxAddress + " (ICE/TCP)" str += ", " + m.LocalTCPAddress + " (ICE/TCP)"
} }
m.Log(logger.Info, str) m.Log(logger.Info, str)
if m.metrics != nil { if m.Metrics != nil {
m.metrics.webRTCManagerSet(m) m.Metrics.webRTCManagerSet(m)
} }
go m.run() go m.run()
return m, nil return nil
} }
// Log is the main logging function. // Log is the main logging function.
func (m *webRTCManager) Log(level logger.Level, format string, args ...interface{}) { func (m *webRTCManager) Log(level logger.Level, format string, args ...interface{}) {
m.parent.Log(level, "[WebRTC] "+format, args...) m.Parent.Log(level, "[WebRTC] "+format, args...)
} }
func (m *webRTCManager) close() { func (m *webRTCManager) close() {
@ -336,12 +315,12 @@ outer:
case req := <-m.chNewSession: case req := <-m.chNewSession:
sx := newWebRTCSession( sx := newWebRTCSession(
m.ctx, m.ctx,
m.writeQueueSize, m.WriteQueueSize,
m.api, m.api,
req, req,
&wg, &wg,
m.externalCmdPool, m.ExternalCmdPool,
m.pathManager, m.PathManager,
m, m,
) )
m.sessions[sx] = struct{}{} m.sessions[sx] = struct{}{}
@ -441,9 +420,9 @@ func (m *webRTCManager) findSessionByUUID(uuid uuid.UUID) *webRTCSession {
} }
func (m *webRTCManager) generateICEServers() ([]pwebrtc.ICEServer, error) { func (m *webRTCManager) generateICEServers() ([]pwebrtc.ICEServer, error) {
ret := make([]pwebrtc.ICEServer, len(m.iceServers)) ret := make([]pwebrtc.ICEServer, len(m.ICEServers))
for i, server := range m.iceServers { for i, server := range m.ICEServers {
if server.Username == "AUTH_SECRET" { if server.Username == "AUTH_SECRET" {
expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix() expireDate := time.Now().Add(webrtcTurnSecretExpiration).Unix()

44
internal/protocols/webrtc/api.go

@ -99,35 +99,45 @@ var audioCodecs = []webrtc.RTPCodecParameters{
// APIConf is the configuration passed to NewAPI(). // APIConf is the configuration passed to NewAPI().
type APIConf struct { type APIConf struct {
ICEInterfaces []string ICEUDPMux ice.UDPMux
ICEHostNAT1To1IPs []string ICETCPMux ice.TCPMux
ICEUDPMux ice.UDPMux LocalRandomUDP bool
ICETCPMux ice.TCPMux IPsFromInterfaces bool
IPsFromInterfacesList []string
AdditionalHosts []string
} }
// NewAPI allocates a webrtc API. // NewAPI allocates a webrtc API.
func NewAPI(conf APIConf) (*webrtc.API, error) { func NewAPI(cnf APIConf) (*webrtc.API, error) {
settingsEngine := webrtc.SettingEngine{} settingsEngine := webrtc.SettingEngine{}
if len(conf.ICEInterfaces) != 0 { settingsEngine.SetInterfaceFilter(func(iface string) bool {
settingsEngine.SetInterfaceFilter(func(iface string) bool { return cnf.IPsFromInterfaces && (len(cnf.IPsFromInterfacesList) == 0 ||
return stringInSlice(iface, conf.ICEInterfaces) stringInSlice(iface, cnf.IPsFromInterfacesList))
}) })
}
settingsEngine.SetAdditionalHosts(cnf.AdditionalHosts)
var networkTypes []webrtc.NetworkType
if len(conf.ICEHostNAT1To1IPs) != 0 { // always enable UDP in order to support STUN/TURN
settingsEngine.SetNAT1To1IPs(conf.ICEHostNAT1To1IPs, webrtc.ICECandidateTypeHost) networkTypes = append(networkTypes, webrtc.NetworkTypeUDP4)
if cnf.ICEUDPMux != nil {
settingsEngine.SetICEUDPMux(cnf.ICEUDPMux)
} }
if conf.ICEUDPMux != nil { if cnf.ICETCPMux != nil {
settingsEngine.SetICEUDPMux(conf.ICEUDPMux) settingsEngine.SetICETCPMux(cnf.ICETCPMux)
networkTypes = append(networkTypes, webrtc.NetworkTypeTCP4)
} }
if conf.ICETCPMux != nil { if cnf.LocalRandomUDP {
settingsEngine.SetICETCPMux(conf.ICETCPMux) settingsEngine.SetICEUDPRandom(true)
settingsEngine.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4})
} }
settingsEngine.SetNetworkTypes(networkTypes)
mediaEngine := &webrtc.MediaEngine{} mediaEngine := &webrtc.MediaEngine{}
for _, codec := range videoCodecs { for _, codec := range videoCodecs {

10
internal/protocols/webrtc/whip_client.go

@ -33,7 +33,10 @@ func (c *WHIPClient) Publish(
return nil, err return nil, err
} }
api, err := NewAPI(APIConf{}) api, err := NewAPI(APIConf{
LocalRandomUDP: true,
IPsFromInterfaces: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -113,7 +116,10 @@ func (c *WHIPClient) Read(ctx context.Context) ([]*IncomingTrack, error) {
return nil, err return nil, err
} }
api, err := NewAPI(APIConf{}) api, err := NewAPI(APIConf{
LocalRandomUDP: true,
IPsFromInterfaces: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

5
internal/staticsources/webrtc/source_test.go

@ -27,7 +27,10 @@ func whipOffer(body []byte) *pwebrtc.SessionDescription {
} }
func TestSource(t *testing.T) { func TestSource(t *testing.T) {
api, err := webrtc.NewAPI(webrtc.APIConf{}) api, err := webrtc.NewAPI(webrtc.APIConf{
LocalRandomUDP: true,
IPsFromInterfaces: true,
})
require.NoError(t, err) require.NoError(t, err)
pc := &webrtc.PeerConnection{ pc := &webrtc.PeerConnection{

50
mediamtx.yml

@ -190,7 +190,7 @@ hlsDirectory: ''
# Allow publishing and reading streams with the WebRTC protocol. # Allow publishing and reading streams with the WebRTC protocol.
webrtc: yes webrtc: yes
# Address of the WebRTC listener. # Address of the WebRTC HTTP listener.
webrtcAddress: :8889 webrtcAddress: :8889
# Enable TLS/HTTPS on the WebRTC server. # Enable TLS/HTTPS on the WebRTC server.
webrtcEncryption: no webrtcEncryption: no
@ -208,34 +208,30 @@ webrtcAllowOrigin: '*'
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
webrtcTrustedProxies: [] webrtcTrustedProxies: []
# List of ICE servers. # Address of a local UDP listener that will receive connections.
webrtcICEServers2: # Use a blank string to disable.
# URL can point to a STUN, TURN or TURNS server. webrtcLocalUDPAddress: :8189
# STUN servers are used to obtain the public IP of server and clients. They are # Address of a local TCP listener that will receive connections.
# needed when server and clients are on different LANs. # This is disabled by default since TCP is less efficient than UDP and
# TURN/TURNS servers are needed when a direct connection between server and # introduces a progressive delay when network is congested.
# clients is not possible. All traffic is routed through them. webrtcLocalTCPAddress: ''
- url: stun:stun.l.google.com:19302 # WebRTC clients need to know the IP of the server.
# Gather IPs from interfaces and send them to clients.
webrtcIPsFromInterfaces: yes
# List of interfaces whose IPs will be sent to clients.
# An empty value means to use all available interfaces.
webrtcIPsFromInterfacesList: []
# List of additional hosts or IPs to send to clients.
webrtcAdditionalHosts: []
# ICE servers. Needed only when local listeners can't be reached by clients.
# STUN servers allows to obtain and share the public IP of the server.
# TURN/TURNS servers forces all traffic through them.
webrtcICEServers2: []
# - url: stun:stun.l.google.com:19302
# if user is "AUTH_SECRET", then authentication is secret based. # if user is "AUTH_SECRET", then authentication is secret based.
# the secret must be inserted into the password field. # the secret must be inserted into the password field.
username: '' # username: ''
password: '' # password: ''
# List of interfaces whose IPs will be sent to clients
# to establish a connection. An empty list means all interfaces.
webrtcICEInterfaces: []
# List of public IP addresses that are to be used as a host.
# This is used typically for servers that are behind 1:1 D-NAT.
webrtcICEHostNAT1To1IPs: []
# Address of a ICE UDP listener in format host:port.
# If filled, ICE traffic will pass through a single UDP port,
# allowing the deployment of the server inside a container or behind a NAT.
webrtcICEUDPMuxAddress:
# Address of a ICE TCP listener in format host:port.
# If filled, ICE traffic will pass through a single TCP port,
# allowing the deployment of the server inside a container or behind a NAT.
# Using this setting forces usage of the TCP protocol, which is not
# optimal for WebRTC.
webrtcICETCPMuxAddress:
############################################### ###############################################
# Global settings -> SRT # Global settings -> SRT

Loading…
Cancel
Save