Skip to content

Commit eea68fa

Browse files
committed
add server/client mode
1 parent af741fa commit eea68fa

File tree

2 files changed

+87
-22
lines changed

2 files changed

+87
-22
lines changed

README.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,39 @@
1313
- **Network Bonding**: Combine multiple internet connections to increase bandwidth and reliability, minimizing the impact of packet loss from any single connection.
1414
- **Intelligent Automatic Scene Switching**: `go-irl` uses detailed SRT statistics like **packet loss** to make smarter switching decisions. It automatically switches to a predefined "offline" scene when network quality degrades and seamlessly returns to your main scene once the connection stabilizes.
1515
- **Real-time Health Monitoring**: Get a clear, visual overview of your stream's performance with live statistics displayed directly in OBS.
16+
- **Flexible Deployment Options**: Supports multiple operation modes including standalone mode for simple setups, and server/client mode for scenarios where port forwarding is not possible, allowing you to deploy the server component on a VPS while running the client locally.
1617

1718
## Command Line Options
1819

1920
The `go-irl` application supports several command line options to customize its behavior:
2021

2122
### Available Options
2223

24+
- **`-mode`** (default: `standalone`)
25+
Operation mode for the application. Available modes:
26+
- **`standalone`**: Default mode. Runs both SRTLA server and SRT proxy on the same machine. Use this when you can open ports directly on your streaming computer.
27+
- **`server`**: Runs only the SRTLA server component. Use this when deploying on a VPS or cloud server with public IP access.
28+
- **`client`**: Runs the SRT proxy, browser source, and WebSocket server. Use this on your local machine when the SRTLA server is running on a remote VPS.
29+
30+
**Note:** Use server/client mode when you cannot open ports on your home network due to router restrictions, ISP limitations, or firewall policies. In this setup, deploy the server component on a VPS or cloud server with public IP access, and run the client component locally where OBS is installed.
31+
32+
- **`-srtPort`** (required for `server` and `clent` modes, default: `5001`)
33+
SRT port for communication between server and client modes. In server mode, this is the port where the SRT stream will be output. In client mode, this is the port where the client will connect to receive the SRT stream from the server.
34+
2335
- **`-bs-port`** (default: `9999`)
24-
Port for the Browser Source web application. This is the port where the web interface for displaying stream statistics will be served.
36+
Port for the Browser Source web application. This is the port where the web interface for displaying stream statistics will be served. Available in `client` and `standalone` modes.
2537

2638
- **`-udp-port`** (default: `5002`)
27-
Port for the UDP downstream. This is the port where the processed stream will be output for OBS to consume.
39+
Port for the UDP downstream. This is the port where the processed stream will be output for OBS to consume. Available in `client` and `standalone` modes.
2840

2941
- **`-ws-port`** (default: `8888`)
30-
WebSocket server port. This port is used for real-time communication between the stream processor and the browser source for displaying statistics and enabling automatic scene switching.
42+
WebSocket server port. This port is used for real-time communication between the stream processor and the browser source for displaying statistics and enabling automatic scene switching. Available in `client` and `standalone` modes.
3143

3244
- **`-srtla-port`** (default: `5000`)
33-
Port for the SRTLA upstream. This is the port where your mobile streaming client (IRL Pro, Moblin, BELABOX, etc.) will connect to send the bonded stream.
45+
Port for the SRTLA upstream. This is the port where your mobile streaming client (IRL Pro, Moblin, BELABOX, etc.) will connect to send the bonded stream. Available in `server` and `standalone` modes.
3446

3547
- **`-passphrase`** (default: `""`)
36-
Optional passphrase for SRT encryption. When set, both the server and client must use the same passphrase to establish a secure encrypted connection. This adds an extra layer of security to your stream.
37-
38-
- **`-verbose`** (default: `false`)
39-
Enable verbose logging in SRTLA. Use this flag to get detailed logging information for troubleshooting connection issues.
48+
Optional passphrase for SRT encryption. When set, both the server and client must use the same passphrase to establish a secure encrypted connection. This adds an extra layer of security to your stream. Available in `client` and `standalone` modes.
4049

4150
## Getting Started
4251

@@ -112,7 +121,6 @@ First, configure OBS to receive the stream and use the bridge for stats and scen
112121
113122
<img width="800" src="https://github.com/user-attachments/assets/6bb9e601-a2e1-453c-98e0-ea6488f838e4" />
114123
115-
116124
---
117125
118126
### Part 3: Run Program

main.go

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ import (
1111
)
1212

1313
var (
14-
bsPort = flag.Int("bs-port", 9999, "Port for the Browser Source web app")
15-
toAddr = flag.Int("udp-port", 5002, "Port for the UDP down stream")
16-
wsPort = flag.Int("ws-port", 8888, "WebSocket server port")
17-
srtlaPort = flag.Int("srtla-port", 5000, "Port for the SRTLA upstream")
18-
passphrase = flag.String("passphrase", "", "Passphrase for SRT stream encryption")
19-
verbose = flag.Bool("verbose", false, "Enable verbose logging in srtla")
14+
mode = flag.String("mode", "", "Operation mode: server | client | standalone (default: standalone)")
15+
srtPort = flag.Int("srtPort", 5001, "SRT port (standalone/server)")
16+
17+
srtlaPort = flag.Int("srtla-port", 5000, "Port for the SRTLA upstream (standalone/server)")
18+
19+
bsPort = flag.Int("bs-port", 9999, "Port for the Browser Source web app (client/standalone)")
20+
wsPort = flag.Int("ws-port", 8888, "WebSocket server port (client/standalone)")
21+
udpPort = flag.Int("udp-port", 5002, "Port for the UDP down stream (client/standalone)")
22+
passphrase = flag.String("passphrase", "", "Passphrase for SRT stream encryption (client/standalone)")
23+
24+
verbose = flag.Bool("verbose", false, "Enable verbose logging in srtla (server/standalone)")
2025
)
2126

2227
var logo = `
@@ -47,35 +52,87 @@ func main() {
4752

4853
fmt.Println(logo)
4954

55+
switch *mode {
56+
case "server":
57+
runServerMode()
58+
case "client":
59+
runClientMode()
60+
case "standalone", "":
61+
runStandaloneMode()
62+
default:
63+
log.Fatalf("ERROR: unknown -mode '%s' (expected server|client|standalone)", *mode)
64+
}
65+
}
66+
67+
func runServerMode() {
68+
if *srtPort <= 0 || *srtPort > 65535 {
69+
log.Fatalf("ERROR: server mode requires -srtPort (1-65535)")
70+
}
71+
72+
log.Printf("[server mode] SRTLA listen port: %d Output SRT port: %d", *srtlaPort, *srtPort)
73+
74+
go runSrtla(uint(*srtlaPort), "0.0.0.0", uint(*srtPort), *verbose)
75+
76+
waitForSignal()
77+
}
78+
79+
func runClientMode() {
80+
if *srtPort <= 0 || *srtPort > 65535 {
81+
log.Fatalf("ERROR: client mode requires -srtPort (1-65535)")
82+
}
5083
if *passphrase != "" && len(*passphrase) < 10 {
51-
log.Fatalf("Passphrase must be at least 10 characters long")
84+
log.Fatalf("ERROR: Passphrase must be at least 10 characters long")
85+
}
86+
if *passphrase == "" {
87+
log.Println("WARNING: No passphrase set. SRT stream will be unencrypted.")
5288
}
5389

90+
fromAddr := fmt.Sprintf("srt://0.0.0.0:%d?mode=listener", *srtPort)
91+
if *passphrase != "" {
92+
fromAddr = fmt.Sprintf("srt://0.0.0.0:%d?mode=listener&passphrase=%s", *srtPort, *passphrase)
93+
}
94+
95+
log.Printf("[client mode] Listening SRT on %s", fromAddr)
96+
97+
go runBrowserSource(*bsPort)
98+
srtDoneChan := runSrtProxy(fromAddr, fmt.Sprintf("udp://127.0.0.1:%d", *udpPort), *wsPort)
99+
waitForEither(srtDoneChan)
100+
}
101+
102+
func runStandaloneMode() {
103+
if *passphrase != "" && len(*passphrase) < 10 {
104+
log.Fatalf("ERROR: Passphrase must be at least 10 characters long")
105+
}
54106
if *passphrase == "" {
55107
log.Println("WARNING: No passphrase set. SRT stream will be unencrypted.")
56108
}
57109

58110
internalSrtPort, err := getFreePort()
59111
if err != nil {
60-
log.Fatalf("Failed to find a free port for internal SRT: %v", err)
112+
log.Fatalf("ERROR: failed to allocate internal SRT port: %v", err)
61113
}
62114

63-
log.Printf("Using dynamic port %d for internal SRT communication.", internalSrtPort)
64-
65115
fromAddr := fmt.Sprintf("srt://127.0.0.1:%d?mode=listener", internalSrtPort)
66116
if *passphrase != "" {
67117
fromAddr = fmt.Sprintf("srt://127.0.0.1:%d?mode=listener&passphrase=%s", internalSrtPort, *passphrase)
68118
}
69119

70120
go runBrowserSource(*bsPort)
71-
72121
go runSrtla(uint(*srtlaPort), "127.0.0.1", uint(internalSrtPort), *verbose)
122+
srtDoneChan := runSrtProxy(fromAddr, fmt.Sprintf("udp://127.0.0.1:%d", *udpPort), *wsPort)
123+
waitForEither(srtDoneChan)
124+
}
73125

74-
srtDoneChan := runSrtProxy(fromAddr, fmt.Sprintf("udp://127.0.0.1:%d", *toAddr), *wsPort)
75-
126+
func waitForSignal() {
76127
signalChan := make(chan os.Signal, 1)
77128
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
129+
<-signalChan
130+
log.Println("Shutdown signal received, exiting.")
131+
}
78132

133+
func waitForEither(srtDoneChan <-chan error) {
134+
signalChan := make(chan os.Signal, 1)
135+
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
79136
select {
80137
case err := <-srtDoneChan:
81138
if err != nil {

0 commit comments

Comments
 (0)