Skip to content

Latest commit

 

History

History
260 lines (188 loc) · 8.32 KB

File metadata and controls

260 lines (188 loc) · 8.32 KB

Getting Started

This guide walks you through building, running, and testing the go-rtmp server from scratch.

Prerequisites

  • Go 1.21+ installed (download)
  • FFmpeg installed (provides ffmpeg and ffplay for testing)
  • Optionally: OBS Studio for live streaming from a camera/screen

Build

cd go-rtmp
go build -o rtmp-server ./cmd/rtmp-server

On Windows this produces rtmp-server.exe.

Run

Basic Server

./rtmp-server -listen :1935 -log-level info

The server is now accepting RTMP connections on port 1935.

With Recording

mkdir -p recordings
./rtmp-server -listen :1935 -log-level info -record-all true -record-dir ./recordings

Every published stream will be saved as an FLV file in the recordings/ directory.

With Relay (Multi-Destination)

./rtmp-server -listen :1935 -relay-to rtmp://cdn1.example.com/live/key -relay-to rtmp://cdn2.example.com/live/key

The server will forward all incoming media to the specified destinations.

With RTMPS (TLS Encryption)

# Generate a self-signed certificate (for testing)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
  -nodes -keyout key.pem -out cert.pem -days 365 -subj "/CN=localhost"

# Run with both RTMP (plaintext) and RTMPS (encrypted)
./rtmp-server -listen :1935 -tls-listen :443 -tls-cert cert.pem -tls-key key.pem

The server will accept plaintext RTMP on port 1935 and encrypted RTMPS on port 443 simultaneously.

For production, use certificates from Let's Encrypt or another CA:

./rtmp-server -listen :1935 \
  -tls-listen :443 \
  -tls-cert /etc/letsencrypt/live/stream.example.com/fullchain.pem \
  -tls-key /etc/letsencrypt/live/stream.example.com/privkey.pem

Streaming clients use rtmps:// URLs:

# Publish over RTMPS
ffmpeg -re -i test.mp4 -c copy -f flv rtmps://localhost:443/live/test

# Watch over RTMPS
ffplay rtmps://localhost:443/live/test

OBS Studio: Set Server to rtmps://your-server:443/live and Stream Key as usual.

With Event Hooks

# Log all events as JSON to stderr (for log pipelines)
./rtmp-server -listen :1935 -hook-stdio-format json

# Call a webhook when a stream starts publishing
./rtmp-server -listen :1935 -hook-webhook "publish_start=https://api.example.com/on-publish"

# Run a script when a client connects
./rtmp-server -listen :1935 -hook-script "connection_accept=/opt/scripts/on-connect.sh"

# Combine multiple hooks
./rtmp-server -listen :1935 \
  -hook-stdio-format json \
  -hook-webhook "publish_start=https://api.example.com/on-publish" \
  -hook-script "connection_accept=/opt/scripts/on-connect.sh"

Available event types: connection_accept, connection_close, publish_start, play_start, codec_detected, auth_failed.

With Metrics

# Enable metrics endpoint on port 8080
./rtmp-server -listen :1935 -metrics-addr :8080

Query metrics at http://localhost:8080/debug/vars — returns JSON with all RTMP counters (connections, publishers, subscribers, media bytes, relay stats, uptime).

With Authentication

# Static tokens via CLI flags
./rtmp-server -listen :1935 \
  -auth-mode token \
  -auth-token "live/stream1=secret123" \
  -auth-token "live/camera1=cam_token"

# Token file (JSON: {"live/stream1": "secret123"})
./rtmp-server -listen :1935 -auth-mode file -auth-file tokens.json

# Webhook callback (POST JSON to your auth service)
./rtmp-server -listen :1935 -auth-mode callback -auth-callback https://auth.example.com/validate

When authentication is enabled, clients must include a token in the stream name:

# Publish with token
ffmpeg -re -i test.mp4 -c copy -f flv "rtmp://localhost:1935/live/stream1?token=secret123"

# Play with token
ffplay "rtmp://localhost:1935/live/stream1?token=secret123"

OBS Studio: set Server to rtmp://localhost:1935/live and Stream Key to stream1?token=secret123.

All CLI Flags

Flag Default Description
-listen :1935 TCP address to listen on
-log-level info Log verbosity: debug, info, warn, error
-record-all false Record all published streams to FLV files
-record-dir recordings Directory for FLV recordings
-chunk-size 4096 Outbound chunk payload size (1-65536 bytes)
-relay-to (none) RTMP URL to relay streams to (repeatable)
-auth-mode none Authentication mode: none, token, file, callback
-auth-token (none) Stream token: streamKey=token (repeatable, for token mode)
-auth-file (none) Path to JSON token file (for file mode)
-auth-callback (none) Webhook URL for auth validation (for callback mode)
-auth-callback-timeout 5s Auth callback HTTP timeout
-hook-script (none) Shell hook: event_type=/path/to/script (repeatable)
-hook-webhook (none) Webhook: event_type=https://url (repeatable)
-hook-stdio-format (disabled) Stdio output format: json or env
-hook-timeout 30s Hook execution timeout
-hook-concurrency 10 Max concurrent hook executions
-metrics-addr (disabled) HTTP address for metrics endpoint (e.g. :8080). Empty = disabled
-version Print version and exit

Test with FFmpeg

Publish a Test Stream

# Stream a local video file to the server
ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost:1935/live/test

# Or generate a test pattern (no video file needed)
ffmpeg -re -f lavfi -i testsrc=size=640x480:rate=30 \
       -f lavfi -i sine=frequency=440:sample_rate=44100 \
       -c:v libx264 -preset ultrafast -tune zerolatency \
       -c:a aac -f flv rtmp://localhost:1935/live/test

# H.265 via Enhanced RTMP (requires FFmpeg 6.1+ with libx265)
ffmpeg -re -f lavfi -i testsrc=size=640x480:rate=30 \
       -f lavfi -i sine=frequency=440:sample_rate=44100 \
       -c:v libx265 -preset ultrafast \
       -c:a aac -f flv rtmp://localhost:1935/live/test

Subscribe (Watch the Stream)

ffplay rtmp://localhost:1935/live/test

Multiple Subscribers

Open several terminals and run ffplay in each — they all receive the same stream independently:

# Terminal 2
ffplay rtmp://localhost:1935/live/test

# Terminal 3
ffplay rtmp://localhost:1935/live/test

Test with OBS Studio

  1. Open OBS Studio → Settings → Stream
  2. Set Service to "Custom"
  3. Set Server to rtmp://localhost:1935/live
  4. Set Stream Key to mystream
  5. Click "Start Streaming"

The server will log the connection and begin recording/relaying.

Verify Recording

# List recorded files
ls recordings/

# Play a recording
ffplay recordings/live_mystream_20260302_143000.flv

# Check file details
ffprobe recordings/live_mystream_20260302_143000.flv

Run the Test Suite

# All tests
go test ./...

# With verbose output
go test -v ./internal/rtmp/chunk/

# Specific package
go test ./internal/rtmp/server/

# Integration tests only
go test ./tests/integration/

Troubleshooting

Symptom Cause Fix
"connection refused" Server not running Start the server first
Black screen in ffplay Missing sequence headers Restart the publisher — the server caches headers for late joiners
"stream not found" in play Wrong stream key Ensure publisher and subscriber use the same app/streamName
High CPU usage Debug logging Use -log-level info instead of debug
Recording file empty Publisher disconnected before keyframe Stream for at least a few seconds
Connection dropped after ~90s TCP read deadline The server closes idle connections after 90 seconds of silence — ensure the publisher is actively streaming

Connection Management

The server automatically manages zombie connections:

  • Read deadline (90s): If no data arrives from a client within 90 seconds, the connection is closed
  • Write deadline (30s): If the server cannot write to a client within 30 seconds, the connection is dropped

These deadlines reset on each successful I/O operation, so active streams are unaffected.

Next Steps