Базовый Readme, понятные переменные окружения
This commit is contained in:
17
README.md
17
README.md
@@ -1,2 +1,15 @@
|
|||||||
### SFU server
|
### SFU сервер
|
||||||
Сервер для организации видеоконференций на основе WebRTC. Написан на Go и использует библиотеку Pion WebRTC.
|
SFU - Selective Forwarding Unit - это тип медиасервера, который принимает медиа-потоки от участников видеоконференции и пересылает их другим участникам без декодирования и повторного кодирования. Это позволяет снизить нагрузку на сервер и улучшить качество видео для всех участников. Сейчас G365SFU просто пересылает RTP пакеты между участниками, не обрабатывая их содержимое (потому, что оно зашифровано). В будущем планируется добавить возможность обработки слоев улучшения.
|
||||||
|
|
||||||
|
### TURN сервер
|
||||||
|
TURN - Traversal Using Relays around NAT - это протокол, который позволяет устройствам за NAT (Network Address Translation) или брандмауэром устанавливать связь с другими устройствами в интернете. TURN серверы используются для ретрансляции медиа-трафика между участниками видеоконференции, когда прямое соединение между ними невозможно из-за ограничений сети. В G365SFU используется встроенный TURN сервер, который можно включить с помощью переменной окружения `TURN_ALLOW=true`. Он будет слушать на порту 3478 и использовать диапазон портов от 40000 до 50000 для ретрансляции трафика. Параметры сервера, такие как публичный IP, имя пользователя и пароль, также настраиваются через переменные окружения. TURN сервер обеспечивает надежную связь между участниками звонка, даже если они находятся за NAT.
|
||||||
|
|
||||||
|
# Установка
|
||||||
|
Для начала, нам необходимо открыть порты 30000-39999 для SFU и 40000-50000 для TURN сервера (по умолчанию, если перенастраивается .env то нужно указать другие). Это можно сделать с помощью команды `ufw`:
|
||||||
|
```bash
|
||||||
|
sudo ufw allow 30000:39999/udp
|
||||||
|
sudo ufw allow 40000:50000/udp
|
||||||
|
sudo ufw allow 30000:39999/tcp
|
||||||
|
sudo ufw allow 40000:50000/tcp
|
||||||
|
sudo ufw allow 3478/tcp
|
||||||
|
```
|
||||||
31
boot/boot.go
31
boot/boot.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"g365sfu/socket"
|
"g365sfu/socket"
|
||||||
connection "g365sfu/socket/struct"
|
connection "g365sfu/socket/struct"
|
||||||
"g365sfu/turn"
|
"g365sfu/turn"
|
||||||
|
"g365sfu/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -32,18 +33,26 @@ func Bootstrap() {
|
|||||||
sfu.OnServerOffer = OnServerOffer
|
sfu.OnServerOffer = OnServerOffer
|
||||||
sfu.OnRoomDelete = OnRoomDelete
|
sfu.OnRoomDelete = OnRoomDelete
|
||||||
sfu.OnPeerDisconnected = OnPeerDisconnected
|
sfu.OnPeerDisconnected = OnPeerDisconnected
|
||||||
turnServer, err := turn.Start(turn.Config{
|
if os.Getenv("TURN_ALLOW") == "true" {
|
||||||
ListenAddr: "0.0.0.0:3478",
|
turnServer, err := turn.Start(turn.Config{
|
||||||
PublicIP: os.Getenv("TURN_PUBLIC_IP"),
|
ListenAddr: "0.0.0.0:3478",
|
||||||
Realm: "g365sfu",
|
PublicIP: os.Getenv("TURN_PUBLIC_IP"),
|
||||||
Username: os.Getenv("TURN_USER"),
|
Realm: "g365sfu",
|
||||||
Password: os.Getenv("TURN_PASS"),
|
Username: os.Getenv("TURN_USER"),
|
||||||
})
|
Password: os.Getenv("TURN_PASS"),
|
||||||
if err != nil {
|
MinRelayPort: uint16(utils.AtoiOrDefault(os.Getenv("TURN_PORT_RANGE_FROM"), 40000)),
|
||||||
logger.LogWarnMessage("TURN start failed: " + err.Error())
|
MaxRelayPort: uint16(utils.AtoiOrDefault(os.Getenv("TURN_PORT_RANGE_TO"), 50000)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.LogWarnMessage("error while starting TURN server: " + err.Error())
|
||||||
|
logger.LogInfoMessage("starting without TURN server, peer connections may fail if clients are behind symmetric NATs")
|
||||||
|
} else {
|
||||||
|
logger.LogInfoMessage("server TURN started at 0.0.0.0:3478")
|
||||||
|
defer turnServer.Close()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.LogInfoMessage("TURN started on 0.0.0.0:3478")
|
// TURN сервер выключен в конфиге, что может влиять на соединение некоторых пользователей
|
||||||
defer turnServer.Close()
|
logger.LogInfoMessage("starting without TURN server, peer connections may fail if clients are behind symmetric NATs")
|
||||||
}
|
}
|
||||||
logger.LogInfoMessage("server started at x.x.x.x:" + port)
|
logger.LogInfoMessage("server started at x.x.x.x:" + port)
|
||||||
http.ListenAndServe(":"+port, nil)
|
http.ListenAndServe(":"+port, nil)
|
||||||
|
|||||||
15
sfu/sfu.go
15
sfu/sfu.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"g365sfu/logger"
|
"g365sfu/logger"
|
||||||
connection "g365sfu/socket/struct"
|
connection "g365sfu/socket/struct"
|
||||||
|
"g365sfu/utils"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/pion/interceptor"
|
"github.com/pion/interceptor"
|
||||||
@@ -34,12 +35,12 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func InitWebRTCEngines() {
|
func InitWebRTCEngines() {
|
||||||
publicIP := os.Getenv("PUBLIC_IP")
|
publicIP := os.Getenv("SFU_PUBLIC_IP")
|
||||||
fromPort := os.Getenv("PORT_RANGE_FROM")
|
fromPort := utils.AtoiOrDefault(os.Getenv("SFU_PORT_RANGE_FROM"), 30000)
|
||||||
toPort := os.Getenv("PORT_RANGE_TO")
|
toPort := utils.AtoiOrDefault(os.Getenv("SFU_PORT_RANGE_TO"), 39999)
|
||||||
if publicIP == "" || fromPort == "" || toPort == "" {
|
if publicIP == "" || fromPort == 0 || toPort == 0 {
|
||||||
// Если не указаны необходимые переменные окружения, логируем ошибку и завершаем процесс сервера
|
// Если не указаны необходимые переменные окружения, логируем ошибку и завершаем процесс сервера
|
||||||
logger.LogErrorMessage("PUBLIC_IP, PORT_RANGE_FROM and PORT_RANGE_TO environment variables must be set")
|
logger.LogErrorMessage("SFU_PUBLIC_IP, SFU_PORT_RANGE_FROM and SFU_PORT_RANGE_TO environment variables must be set")
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -50,9 +51,9 @@ func InitWebRTCEngines() {
|
|||||||
_ = webrtc.RegisterDefaultInterceptors(m, i)
|
_ = webrtc.RegisterDefaultInterceptors(m, i)
|
||||||
|
|
||||||
se := webrtc.SettingEngine{}
|
se := webrtc.SettingEngine{}
|
||||||
_ = se.SetEphemeralUDPPortRange(40000, 50000)
|
_ = se.SetEphemeralUDPPortRange(uint16(fromPort), uint16(toPort))
|
||||||
|
|
||||||
if publicIP := os.Getenv("PUBLIC_IP"); publicIP != "" {
|
if publicIP := os.Getenv("SFU_PUBLIC_IP"); publicIP != "" {
|
||||||
se.SetICEAddressRewriteRules(webrtc.ICEAddressRewriteRule{
|
se.SetICEAddressRewriteRules(webrtc.ICEAddressRewriteRule{
|
||||||
External: []string{publicIP},
|
External: []string{publicIP},
|
||||||
AsCandidateType: webrtc.ICECandidateTypeHost,
|
AsCandidateType: webrtc.ICECandidateTypeHost,
|
||||||
|
|||||||
36
turn/turn.go
36
turn/turn.go
@@ -19,6 +19,25 @@ type Config struct {
|
|||||||
Realm string
|
Realm string
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
|
|
||||||
|
MinRelayPort uint16
|
||||||
|
MaxRelayPort uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func relayGen(ip net.IP, minPort, maxPort uint16) pionturn.RelayAddressGenerator {
|
||||||
|
if minPort != 0 && maxPort != 0 && minPort <= maxPort {
|
||||||
|
return &pionturn.RelayAddressGeneratorPortRange{
|
||||||
|
RelayAddress: ip,
|
||||||
|
Address: "0.0.0.0",
|
||||||
|
MinPort: minPort,
|
||||||
|
MaxPort: maxPort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pionturn.RelayAddressGeneratorStatic{
|
||||||
|
RelayAddress: ip,
|
||||||
|
Address: "0.0.0.0",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(cfg Config) (*Server, error) {
|
func Start(cfg Config) (*Server, error) {
|
||||||
@@ -38,6 +57,8 @@ func Start(cfg Config) (*Server, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rg := relayGen(ip, cfg.MinRelayPort, cfg.MaxRelayPort)
|
||||||
|
|
||||||
srv, err := pionturn.NewServer(pionturn.ServerConfig{
|
srv, err := pionturn.NewServer(pionturn.ServerConfig{
|
||||||
Realm: cfg.Realm,
|
Realm: cfg.Realm,
|
||||||
AuthHandler: func(username, realm string, srcAddr net.Addr) ([]byte, bool) {
|
AuthHandler: func(username, realm string, srcAddr net.Addr) ([]byte, bool) {
|
||||||
@@ -48,23 +69,18 @@ func Start(cfg Config) (*Server, error) {
|
|||||||
},
|
},
|
||||||
PacketConnConfigs: []pionturn.PacketConnConfig{
|
PacketConnConfigs: []pionturn.PacketConnConfig{
|
||||||
{
|
{
|
||||||
PacketConn: udpConn,
|
PacketConn: udpConn,
|
||||||
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
|
RelayAddressGenerator: rg,
|
||||||
RelayAddress: ip,
|
|
||||||
Address: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ListenerConfigs: []pionturn.ListenerConfig{
|
ListenerConfigs: []pionturn.ListenerConfig{
|
||||||
{
|
{
|
||||||
Listener: tcpListener,
|
Listener: tcpListener,
|
||||||
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
|
RelayAddressGenerator: rg,
|
||||||
RelayAddress: ip,
|
|
||||||
Address: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tcpListener.Close()
|
_ = tcpListener.Close()
|
||||||
_ = udpConn.Close()
|
_ = udpConn.Close()
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "math/rand"
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// Генерация случайной строки заданной длины
|
// Генерация случайной строки заданной длины
|
||||||
func RandomString(n int) string {
|
func RandomString(n int) string {
|
||||||
@@ -11,3 +14,14 @@ func RandomString(n int) string {
|
|||||||
}
|
}
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AtoiOrDefault(s string, defaultValue int) int {
|
||||||
|
if s == "" {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user