Базовый Readme, понятные переменные окружения

This commit is contained in:
set
2026-03-17 14:28:15 +02:00
parent e703ac22e6
commit 3c810407db
5 changed files with 84 additions and 31 deletions

View File

@@ -1,2 +1,15 @@
### SFU server
Сервер для организации видеоконференций на основе WebRTC. Написан на Go и использует библиотеку Pion WebRTC.
### SFU сервер
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
```

View File

@@ -9,6 +9,7 @@ import (
"g365sfu/socket"
connection "g365sfu/socket/struct"
"g365sfu/turn"
"g365sfu/utils"
"net/http"
"os"
@@ -32,18 +33,26 @@ func Bootstrap() {
sfu.OnServerOffer = OnServerOffer
sfu.OnRoomDelete = OnRoomDelete
sfu.OnPeerDisconnected = OnPeerDisconnected
turnServer, err := turn.Start(turn.Config{
ListenAddr: "0.0.0.0:3478",
PublicIP: os.Getenv("TURN_PUBLIC_IP"),
Realm: "g365sfu",
Username: os.Getenv("TURN_USER"),
Password: os.Getenv("TURN_PASS"),
})
if err != nil {
logger.LogWarnMessage("TURN start failed: " + err.Error())
if os.Getenv("TURN_ALLOW") == "true" {
turnServer, err := turn.Start(turn.Config{
ListenAddr: "0.0.0.0:3478",
PublicIP: os.Getenv("TURN_PUBLIC_IP"),
Realm: "g365sfu",
Username: os.Getenv("TURN_USER"),
Password: os.Getenv("TURN_PASS"),
MinRelayPort: uint16(utils.AtoiOrDefault(os.Getenv("TURN_PORT_RANGE_FROM"), 40000)),
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 {
logger.LogInfoMessage("TURN started on 0.0.0.0:3478")
defer turnServer.Close()
// TURN сервер выключен в конфиге, что может влиять на соединение некоторых пользователей
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)
http.ListenAndServe(":"+port, nil)

View File

@@ -4,6 +4,7 @@ import (
"errors"
"g365sfu/logger"
connection "g365sfu/socket/struct"
"g365sfu/utils"
"os"
"github.com/pion/interceptor"
@@ -34,12 +35,12 @@ var (
)
func InitWebRTCEngines() {
publicIP := os.Getenv("PUBLIC_IP")
fromPort := os.Getenv("PORT_RANGE_FROM")
toPort := os.Getenv("PORT_RANGE_TO")
if publicIP == "" || fromPort == "" || toPort == "" {
publicIP := os.Getenv("SFU_PUBLIC_IP")
fromPort := utils.AtoiOrDefault(os.Getenv("SFU_PORT_RANGE_FROM"), 30000)
toPort := utils.AtoiOrDefault(os.Getenv("SFU_PORT_RANGE_TO"), 39999)
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)
return
}
@@ -50,9 +51,9 @@ func InitWebRTCEngines() {
_ = webrtc.RegisterDefaultInterceptors(m, i)
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{
External: []string{publicIP},
AsCandidateType: webrtc.ICECandidateTypeHost,

View File

@@ -19,6 +19,25 @@ type Config struct {
Realm string
Username 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) {
@@ -38,6 +57,8 @@ func Start(cfg Config) (*Server, error) {
return nil, err
}
rg := relayGen(ip, cfg.MinRelayPort, cfg.MaxRelayPort)
srv, err := pionturn.NewServer(pionturn.ServerConfig{
Realm: cfg.Realm,
AuthHandler: func(username, realm string, srcAddr net.Addr) ([]byte, bool) {
@@ -48,23 +69,18 @@ func Start(cfg Config) (*Server, error) {
},
PacketConnConfigs: []pionturn.PacketConnConfig{
{
PacketConn: udpConn,
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
RelayAddress: ip,
Address: "0.0.0.0",
},
PacketConn: udpConn,
RelayAddressGenerator: rg,
},
},
ListenerConfigs: []pionturn.ListenerConfig{
{
Listener: tcpListener,
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
RelayAddress: ip,
Address: "0.0.0.0",
},
Listener: tcpListener,
RelayAddressGenerator: rg,
},
},
})
if err != nil {
_ = tcpListener.Close()
_ = udpConn.Close()

View File

@@ -1,6 +1,9 @@
package utils
import "math/rand"
import (
"math/rand"
"strconv"
)
// Генерация случайной строки заданной длины
func RandomString(n int) string {
@@ -11,3 +14,14 @@ func RandomString(n int) string {
}
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
}